const 的引用
- 非常量引用不能指向一个常量对象
const int ci = 1024; int &r2 = ci; // 错误🙅 // 因为r2有可能改变ci的值
- 初始化常量引用时允许使用任意表达式作为初值
int i = 42; const int &r1 = i; // 正确,此时仅仅是不能通过r1修改i i = 54; // 正确,i可以通过其它方式修改,此时r1也等于54 double dval = 3.14; const int &ri = dval; // 正确 // 上面这段的过程如下 const int tmp = dval; const int &ri = temp;
- 函数传参时尽量使用常量引用
int add(int& a, int& b); add(1, 2) // 错误! int add_const(const int& a, const int& b); add_const(1, 2) // 正确! int use_add(const int& a, const int& b) { add(a, b) // 错误! add_const(a, b) // 正确! }
- 不能返回局部对象的引用
const std::string& foo() { std::string s; s = "hello world"; return s; // 错误,引用是某一变量的别名,在函数返回后,变量都消失了,那能返回谁的引用呢? } const std::string foo() { std::string s; s = "hello world"; return s; // 正确,返回的是拷贝 }
std::string& foo(std::string& s) { // 返回左值 return s; } const std::string& foo_const(const std::string& s) { //返回左值,不过是const return s; } std::string& foo_error(const std::string& s) { // 错误的函数!!! return s; } std::string foo_right(const std::string& s) { // 正确的函数,返回右值 return s; } int main() { std::string s = "hello"; foo(s) = "world"; // 引用返回的左值 foo1(s) = "world"; // 错误! std::cout << s << std::endl; std::string& ss = foo_const(s); // 错误!非常量引用不能引用常量 const std::string& ss = foo1(s); // 正确 std::string ss = foo_const(s); // 正确 std::cout << ss << std::endl; return 0; }
const 成员
- 常量对象和重载
this 指针是类中隐式定义的指向类类型的非常量版本的常量指针(始终指向类类型,但是不能被 const 对象使用)。
如果我们需要 const 对象使用成员函数,则需要尽可能将不会改变 this 所指对象但成员函数设置为 const 成员函数。而且,两个成员函数如果仅仅是常量性不同,则可以被重载。
例如:
class A { public: int& value() { std::cout << "This is normal version" << std::endl; return m_value; } const int& value() const { std::cout << "This is const version" << std::endl; return m_value; } private: int m_value = 2; }; void print(const A& a) { std::cout << a.value() << std::endl; // 只能调用const版本 } int main() { A a1; std::cout << a1.value() << std::endl; // 默认使用了非const版本,但也可以使用const版本 const A a2; std::cout << a2.value() << std::endl; // 只能使用const版本 print(a1); return 0; } // 打印结果 // This is normal version // 2 // This is const version // 2 // This is const version // 2
- 避免代码重复
以上的 value
函数的两个版本有着完全相同的函数内容,为了避免代码重复,我们可以使用类型转换:
const int& value() const { std::cout << "This is const version" << std::endl; return m_value; } int& value() { return const_cast<int&> ( static_cast<const A&>(*this).value() ); }
注意⚠️:只能 non-const 版本调用 const 版本,不能反向操作!
也可以把这两个函数的公共部分定义成一个 private 的内联函数,这样不会增加开销也便于维护。
- 使用 mutable
如果想在 const 成员函数内改变成员变量,需要声明成员变量为 mutable。
class A { public: const int& value() const { std::cout << "This is const version" << std::endl; use_time++; // const函数内改变了成员变量 return m_value; } int& value() { return const_cast<int&> ( static_cast<const A&>(*this).value() ); } private: int m_value = 2; mutable int use_time = 0; // int use_time = 0; 被const value()使用会出错! };
- 静态成员 static
静态成员为类的所有对象共享。
静态成员函数不能被声明为 const,因为它们不包含 this 指针。静态成员函数也不能与任何对象绑定。
- copy assignment
如果 class 中含有 reference 成员和 const 成员,class 将拒绝为其生成 copy assignment 操作符。
书评写不出来,发一篇笔记泄愤!
作为一个新手小白,其实还有很多没有看懂,码住慢慢学