Effective C++ 读书笔记 Item5 了解 C++默默编写并调用哪些函数

C++学习笔记 专栏收录该内容
67 篇文章 2 订阅

在C++中,编译器会自动生成一些你没有显式定义的函数,它们包括:构造函数、析构函数、复制构造函数、=运算符。 有时为了符合既有设计,我们不希望自动生成这些函数,我们可以把它们显式声明为private。 此时在使用这些类的客户看来,它们就像不存在一样。

class Empty{
public:
    // 默认构造函数
    Empty(){}   
    // 拷贝构造函数
    Empty(const Empty& rhs){}   
    // 析构函数
    ~Empty(){}
    // 赋值运算符
    Empty& operator=(const Empty& rhs){}
};

调用时机

当我们没有显式地定义上述这四种函数时,编译器会自动帮我们定义。这些函数它们调用的时机如下:

构造函数:对象定义;使用其他兼容的类型初始化对象时(可使用 explicit 来避免这种情况)
复制构造函数:用一个对象来初始化另一对象时;传入对象参数时;返回对象时;
析构函数:作用域结束(包括函数返回)时;delete
=运算符:一个对象赋值给另一对象
为了更清晰地说明它们的调用时机,来个例子吧:

Empty e1;               // 默认构造函数
Empty e2(e1);           // 拷贝构造函数
Empty e3 = e1;          // 拷贝构造函数
e2 = e1;                // = 运算符
 
void func(Empty e){     // 拷贝构造函数,拷贝一份参数对象
    return e;           // 拷贝构造函数,拷贝一份返回对象
                        // 析构函数,拷贝得到的参数对象被析构
}
 
e2 = func(e1);          // = 运算符
                        // 析构函数,返回值被析构

引用成员

当对象包含引用成员时,拷贝和赋值行为将会变得非常有趣,考虑这样一个类:

class Person{
public:
    string & name;
    Person(string& str): name(str){ }
};
string s1 = "alice", s2 = "bob";
Person p1(s1), p2(s2);
 
s1 = s2;

而这样的操作就相当于:

int  a=3;
int& b=a;
int  c=7;
int& d=c;
b=d;           //编译器在此当然会报错

赋值后,p1.name会指向p2.name吗?我们知道在C++中引用本身是不可修改的。 即使p1.name指向了p2.name,那么对p1.name的赋值将会影响到p2? 于是,C++拒绝编译上述代码,此时我们需要手动定义一个赋值运算符。

说来神奇,拷贝构造函数也存在同样的问题,编译器却从不抱怨。可以正常编译,并且两个引用指向同一对象。
 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:书香水墨 设计师:CSDN官方博客 返回首页

打赏作者

Allen Chou

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值