类中的引用与常量的初始化问题(含测试代码)

#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)。
他们的作用就是:当函数需要返回一个对象的时候,如果自己创建一个临时对象用户返回,那么这个临时对象会消耗一个构造函数的调用、一个拷贝构造函数的调用以及一个析构函数的调用的代价。
而如果稍微做一点优化,就可以将成本降低到一个构造函数的代价,也就是将内容直接构造到左值中,中间不生成临时变量。

*/

 

posted @ 2023-04-20 16:11  ztlsw  阅读(17)  评论(0编辑  收藏  举报