Effective C++笔记(2)

Effective C++笔记
第二章 构造/析构/copy赋值 05~12

P5:了解C++默默编写并调用哪些函数

1:编译器可以暗自为class创建 default构造函数、copy构造函数、copy assignment操作符、析构函数。 唯有这些函数被需要调用,他们才会被编译器创建出来。
2:如果你打算在一个“内含引用成员”或者“内含const成员”的class内支持赋值操作,你必须自己定义copy assignment操作符。
3:如果base classes将copy assignment操作符声明为private,编译器将拒绝为子类生成copy assignment操作符。
4:编译器产生的析构函数是个non-virtual函数。

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

1:为驳回编译器自动提供的功能,可以将相应的成员函数声明为private并且不予实现。或者使用Uncopyable这样的base class方法。

class Uncopyable{
    protected:              //允许derived对象构造和析构
        Uncopyable(){}
        ~Uncopyable(){}
    private:                //但是阻止copying
        Uncopyable( const Uncopyable& );
        Uncopyable& operator=(const Uncopyable&);

};

P7:为多态基类声明 virtual 析构函数

1:如果析构函数不是virtual,则当子类对象是经由一个base class指针析构的时候,他的derived部分会没被销毁。
2:多态性质的base class应该声明一个virtual析构函数。如果class带有virtual函数,它就应该有一个virtual析构函数。
3:class设计的目的如果不是作为base class使用,或不是为了具备多态性,就不该声明virtual析构函数。 STL容器vector,list,set,string等都是non-virtual析构。
4:具有多态性的base class的设计目的是为了用来“通过base class接口处理derive对象”。
5:析构函数的运作方式是,最深层派生的那个class其析构函数最先被调用,然后是每个base class的析构函数被调用。
6:抽象类的virtual析构函数应该有一份定义,原因是第5条在子类的析构函数中会调用抽象类的析构函数。

virtual ~AWOW()=0;  //声明抽象析构函数

AWOW::~AWOW()(){}  //抽象析构函数的定义

P8:别让异常逃离析构函数

1:析构函数如果可能抛出异常,应该捕获异常。并且提供一个普通函数给用户机会自己处理该操作。

class DBConn{
    public:
        void close()        //给客户端一个机会处理可能导致异常的行为
        {
            db.close();
            closed = true; 
        }
        ~DBConn()
        {
            if(!closed)
            {
                try{
                    db.close();
                }
                catch(...){
                    //记录下来并结束程序或吞下异常不做处理。
                }
            }
        }
    private:    
        DBConnection db;
        bool closed;
};

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

1:在deviced class对象的base class构造期间,对象的类型还只是base clas对象而不是deviced class对象! virtual函数只会被解析到base class,对象在deviced class的构造函数开始之前不会成为一个deviced class对象。析构函数同样的道理,只是析构顺序自deviced class到base class。
2:可以让deviced class将必要的信息向上传递至base class构造函数去调用non-virtual函数。

P10:令operator= 返回一个 reference to *this

1:令赋值操作符返回一个reference to *this,这样可以实现连锁赋值。如 x=y=z=“str”;

P11:在operator= 中处理自我赋值

1:使用“证同测试”、语句顺序调整、copy-and-swap等方式确保operator=的自我赋值是正确的。
2:确保然后函数如果操作多个对象时,其中有多个对象是同一个对象时,其行为仍然正确。

class Widget{
    void swap(Widget& rhs); //交换*this和rhs的数据,详见P29。
    BitMap* pb;
};

Widget& Widget::operator=(const Widget& rhs)
{
    if(this == &rhs) return *this; //证同测试

    Widget temp(rhs);   //为rhs数据制作一份副本
    swap(temp);         //将*this与副本数据交换;copy-and-swap技术
    return *this;
}
Widget& Widget::operator=(const Widget& rhs)
{
    BitMap* pOrig = pb;
    pb = new BitMap(*rhs.pb);
    delete pOrig;   //这么写的目的是我们需要注意在复制pb前不能删除pb。
    return *this;
}

P12:复制对象时勿忘其每一个成分

1:当编写copying函数时,应确保复制“对象内的所有成员变量”,确保调用所有base class内适当的copying函数复制”所有base class成分”。
2:不要以某个copying函数去实现另一个copying函数,应该把功能放在第三个init函数中去由copying函数调用。

PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
    :Customer(rhs)          //调用base class的copy构造函数
{
    logCall("拷贝构造函数");
}
PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
    logCall("复制操作符");
    Customer::operator=(rhs);   //对base class成分进行赋值操作
    priority = rhs.priority;
    retern *this;   
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值