C++学习知识点记录1
1. auto与decltype区别
auto
- 作用:根据初始化表达式自动推导变量的实际类型。
- 使用场景:
1、简化复杂类型的声明(如迭代器、lambda
表达式等)。
2、类型不重要或类型可能会变化时。
3、希望变量具有与初始化表达式相同的类型。
auto x = 42; // x 的类型为 int
auto y = 3.14; // y 的类型为 double
auto z = add(1, 2); // z 的类型由 add 返回值决定(int)
const int &a = x;
auto b = a; // b 的类型为 int(去掉了 const 和引用)
注:auto
会忽略顶层的 const
和引用。
decltype
- 作用:获取表达式的确切类型(包括引用、
const
等修饰符)。 - 使用场景:
1、需要保留表达式的引用或const
属性。
2、编写泛型代码时,推导某个表达式的类型。
3、在模板元编程中用于类型操作。
int i = 1024;
int &j = i;
decltype(i) x = 2048; // x 的类型为 int
decltype(j) y = i; // y 的类型为 int&(保留了引用)
const int &ci = i;
decltype(ci) z = i; // z 的类型为 const int&
对比总结
特性 | auto | decltype |
---|---|---|
推导依据 | 初始化表达式的值 | 表达式的类型(包括引用、const 等) |
是否保留引用 | 否(退化为值类型) | 是(保留引用) |
是否保留 const | 否(退化为非 const) | 是(保留 const) |
适用场景 | 简化类型声明、通用类型推导 | 泛型编程、精确类型控制 |
例子
template <typename T>
void foo(T& val) {
auto x = val; // x 是 T 的值类型(去掉引用和 const)
decltype(val) y = val; // y 是 T&(保留引用)
}
结论
- 如果你只关心“这个表达式的值是什么类型”,用
auto
。 - 如果你需要“完全保留表达式的类型特性(如引用、
const
)”,用decltype
。
2、左值和右值
定义
- 右值:临时存储对象,没有确定的内存位置。
- 左值:除右值以外的是左值。
举例
int a = 10; // 'a' 是一个左值,'10' 是一个右值
int* p = new int(20); // '*p' 是一个左值
函数返回值为右值。
int foo() {return 2;}
int main()
{
foo() = 2; // error! foo()返回值是右值,不能给右值赋值
return 0;
}
字面量和表达式为右值。
int var;
var = 4; // var是一个左值,左值可以赋值
4 = var; // 错误! '4' 是一个右值,不能赋值
(var + 1) = 4; // 错误! 'var + 1'是一个表达式,是右值,不能赋值
函数返回值也可以为左值。
int globalvar = 20;
int& foo()
{
return globalvar; // 函数返回左值引用
}
int main()
{
foo() = 10; // 左值引用可以赋值
return 0;
}
左值可以转换为右值,但是右值不能被转换成左值。
int a = 1; // a 是左值
int b = 2; // b 是左值
int c = a + b; // + 需要右值,所以 a 和 b 被转换成右值
// + 返回右值
不能将右值赋给左值引用。
std::string& sref = std::string(); // error!
int &ref = 1; // error1
const int &ref1 = 1; // 正确,增加了const限定符
3、四种类型强制转换
static_cast
static_cast
用于基本数据类型的转换,如整型、浮点型之间的转换,也可以用于具有继承关系的类对象之间的转换。它不能进行无关类型之间的转换,例如不能将一个完全不相关的类指针转换为另一个类指针。
double d = 3.14;
int i = static_cast<int>(d); // 将double转换为int
dynamic_cast
dynamic_cas
t主要用于涉及类层次结构的安全向下转型(downcasting),即从基类指针或引用转换为派生类指针或引用。它在运行时检查转换的有效性,如果转换是安全的,则成功;否则,对于指针返回nullptr
,对于引用则抛出std::bad_cast
异常。
class Base { virtual void dummy() {} };
class Derived : public Base {};
Base* b = new Derived;
Derived* d = dynamic_cast<Derived*>(b); // 如果b实际指向的是Derived对象,转换成功
const_cast
const_cast
用于添加或移除变量的const
或volatile
属性。这是唯一可以改变变量是否为const
的方式,但需要注意的是,如果你使用const_cast
移除了某个变量的const
属性并尝试修改它,而该变量实际上是定义为const
的,那么这个行为是未定义的。
const int a = 10;
int* b = const_cast<int*>(&a); // 移除'a'的const属性
reinterpret_cast
reinterpret_cast
是最粗略的类型转换,它基本上只是重新解释了给定的比特模式,而不进行任何类型的检查或转换逻辑。它可以用于指针间、指针与整数间的转换,但这种转换非常危险,除非你确切知道你在做什么,否则不推荐使用。
int a = 0x12345678;
int* p = &a;
long long* q = reinterpret_cast<long long*>(p); // 强制转换为不同类型的指针
这四种类型转换提供了不同的功能和安全性级别。通常建议尽可能使用static_cast
、dynamic_cast
和const_cast
,因为它们提供了编译时期的一些类型检查,并且意图更加明确。而reinterpret_cast
由于其潜在的危险性,应该谨慎使用。