ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Effective C++ 笔记(2)

2020-12-01 08:33:01  阅读:200  来源: 互联网

标签:函数 Effective rhs 笔记 Uncopyable C++ copy class 构造函数


第二部分: 构造/析构/赋值运算

条款05: 了解C++默默编写并调用哪些函数

对于一个类,如果自己没声明,那么编译器会默认生成一个copy构造函数、一个copy assignment操作符和一个析构函数。此外如果你没有声明任何构造函数,编译器还会声明一个default构造函数。
所有这些函数都是public并且inline的。
因此,如果你写下

class Empty {};

这就好像你写下这样的代码

class Empty {
    Empty() { ... }                             //default构造函数
    Empty(const Empty& rhs){ ... }             //copy构造函数
    ~Empty(){ ... }                            //析构函数

    Empty& operator=(const Empty& rhs){ ... } //copy assignment操作符
}
请记住

编译器可以暗自为class创建default构造函数、copy构造函数、copy assignment操作符以及析构函数。

条款06: 若不想使用编译器自动生成的函数, 就该明确拒绝

如果不想编译器支持某个类的copy构造函数或者copy assignment操作符, 可以自己创建它们的空函数,然后声明为private(一般来说,因为private声明,它们不能被调用,一旦menber函数和friend函数调用,则会生成连接错误阻止它们的行为)

不想让menber函数和friend函数的调用到连接阶段才报错?可以创建一个Uncopyable基类,继承它即可。

class Uncopyable {
protected:
    Uncopyable(){}
    ~Uncopyable(){}
private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator= (const Uncopyable&);
}
请记住
  • 为驳回编译器自动提供的机能,可将相应的成员函数声明为private并且不予实现。使用像Uncopyable这样的base class也是一种做法。

条款07: 为多态基类声明virtual析构函数

请记住
  • 带多态性质的基类应该声明一个虚析构函数。如果类带有任何虚函数,它就应该拥有一个虚析构函数。
  • 一个类的设计目的如果不是作为基类使用,或不是为了具备多态性,就不该声明虚析构函数。

条款08: 别让异常逃离析构函数

请记住
  • 析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常, 然后吞下它们(不传播)或者结束程序。
  • 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。

条款09: 绝不在构造和析构过程中调用virtual函数

请记住
  • 在构造和析构期间不要调用virtual函数,因为这类调用从不下降到派生类
struct Super {
    Super() { test(); }
    virtual ~Super() { test(); }
    virtual void test() { std::cerr << "super" << std::endl; }
};

struct Derived : Super {
    void test() override { std::cerr << "derived" << std::endl; }
};

int main() {
    Super *p = new Derived;
    p->test();
    delete p;
}

输出:

super
derived
super

条款10: 令operator=返回一个reference to *this

为了让自定义类型实现如下的连锁赋值

int x, y, z;
x = y = z = 15;

class的赋值操作符必须返回一个reference指向操作符的左侧实参

class Widget{
    public:
    Widget& operator=(const Widget& rhs) { //返回类型是个reference
        ...                                 
        return *this                       //返回左侧对象             
    }
}

这份协议被所有内置类型和标准程序库所提供的类型共同遵守。

请记住:
  • 令赋值操作符返回一个reference to *this

条款11: 在operator=中处理自我赋值

请记住:
  • 确保当对象自我赋值时=有良好行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。
  • 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。

条款12: 复制对象时勿忘其每一个成分

为派生类撰写copying函数的重责大任,必须小心地复制其base class 成分。应该让派生类的copying构造函数调用相应的基类函数:

PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
    : Customer(rhs),
      priority(rhs.priority) {
          logCall("PriorityCustomer copy constructor");
      }
PriorityCustomer&
PriorityCustomer::operator=(const PriorityCustomer& rhs) {
    logCall("PriorityCustomer copy assignment operator");
    Customer::operator=(rhs);
    priority = rhs.priority;
    return *this;
}

当编写一个copying函数,请确保(1)复制所有local成员变量,(2)调用基类内的适当copying函数。

请记住:
  • Copying函数应该确保复制"对象内的所有成员变量"以及"所有base class成分"
  • 不要尝试以某个copying函数实现另一个copying函数。应该将共同机能放进第三个函数,并由两个coping函数共同调用。(不应让copy assignment操作符调用copy构造函数,也不该让copy构造函数调用copy assignment操作符)

标签:函数,Effective,rhs,笔记,Uncopyable,C++,copy,class,构造函数
来源: https://www.cnblogs.com/thhyj/p/14066077.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有