类中的引用与常量的初始化问题(含测试代码)
#include<iostream> #include<string> #include<set> #include<time.h> #include<cstring> #include <vector> #define LL long long #define MAXN 100010 using namespace std; int ask_int = 12; double ask_double = 1.2; /* 前置注意点: 我们定义类中的引用变量,一般是为了捕获类中的成员变量,而不是为了捕获外部变量,因为容易出现未可知的bug 这涉及到引用的底层机制,这里仅做引用的举例用(其实是知道的太晚了,代码写的差不多了),不要这样写代码。 https://zhuanlan.zhihu.com/p/262210907写的很好,给我很大启发 其实我们甚至很少把成员变量定义为引用 */ class A { public: int &lim_num; const int &lim_const_int; const int const_int; int num; int &&right_num; public: //对象中有这些引用不能使用默认构造函数[1] //A() : lim_num(12),right_num(ask_int),const_int(18),lim_const_int(ask_int) {num = 1;cout<<lim_num<<"created"<<endl;} /* 编译错误!注意第一项,没加const的引用不能够指向一个右值,而第二项必须用右值赋值 报错信息:cannot bind rvalue reference of type 'int&&' to lvalue of type 'int' */ //A() : lim_num(ask_double),right_num(ask_double),const_int(18),lim_const_int(20) {} /*编译错误!注意第一项, 假设我们赋予的左值和我们的引用类型不同,那么会进行一次强制类型转换, 这次强制转换会产生一个临时常量 const int limi = (int) ask_double;(也许,总之系统将其视为一个右值,临时变量具有常性) 报错信息:cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int' */ A() : lim_num(ask_int),right_num(15),const_int(18),lim_const_int(20) {num = 1;cout<<"created"<<endl;} A(int a,int b,int c,int d,int e) : lim_num(a),const_int(b),lim_const_int(c),right_num(165){num = d;cout<<"common created"<<endl;} //A(const A &a) : lim_num(a.const_int),const_int(a.const_int),lim_const_int(a.lim_const_int),right_num(move(a.right_num)){num = a.num;cout<<"copy created"<<endl;} /*出现bug,最好不要把引用往外指,这个地方可能是因为构造函数把变量副本压入栈中,然后引用绑定了这个栈的临时位置,栈中弹出的时候,就指向了未定义的位置*/ A(const A &a) : lim_num(num),const_int(a.const_int),lim_const_int(a.lim_const_int),right_num(move(a.right_num)){num = a.num;cout<<"copy created"<<endl;} /*注意最后一项,我们使用move把左值转换成右值*/ A(A &&a)noexcept : lim_num(num),const_int(a.const_int),lim_const_int(a.lim_const_int),right_num(move(a.right_num)){num = a.num;cout<<"move created"<<endl;} /*一定要采用括号赋值的方法,不能在大括号里对常量以及引用进行赋值*/ ~A(){cout<<" deleted"<<endl;} void printing() {cout<<" "<<lim_num<<" "<<const_int<<" "<<lim_const_int<<" "<<right_num<<" "<<num<<endl;} }; A rtti(const A &a) { return a; } int main() { int cxk = 12; //无参测试 //A none_val(); //这种写法只创建一个类的名字,没有任何实际作用 A *none_val = new A(); //这样写就可以,调用无参构造函数 //none_val->func(); //一般测试 A *common_val = new A(ask_int,14,161,18,244); //A copy_val(*common_val); common_val->printing(); //拷贝测试 A copy_val = *common_val; //引用外指出现位置bug,第一个引用参数对象变得混乱 //copy_val.printing(); //移动测试 A move_val(12,15,16,187,258); A las(forward<A>(rtti(move_val))); //las.printing(); /*注意: 我为什么要用forward转换?难道函数返回的不是右值吗? C++11以及许多编辑器都有RVO[2]机制,优化函数返回值,有的还不给关掉 forward是完美转发,证明函数返回确实是右值,同时强转为右值图个方便 */ return 0; } /* [1]凡是有引用类型的成员变量或者常量类型的变量的类,不能有缺省构造函数。 默认构造函数没有对引用成员提供默认的初始化机制,也因此造成引用未初始化的编译错误。 并且必须使用初始化列表或直接赋值进行初始化const对象、引用对象。 [2]RVO(Return Value Optimization,返回值优化),而NRVO是(Named Return Value Optimization)。 他们的作用就是:当函数需要返回一个对象的时候,如果自己创建一个临时对象用户返回,那么这个临时对象会消耗一个构造函数的调用、一个拷贝构造函数的调用以及一个析构函数的调用的代价。 而如果稍微做一点优化,就可以将成本降低到一个构造函数的代价,也就是将内容直接构造到左值中,中间不生成临时变量。 */