zoukankan      html  css  js  c++  java
  • EffectiveC++ 第2章 构造/析构/赋值运算

    我根据自己的理解,对原文的精华部分进行了提炼,并在一些难以理解的地方加上了自己的“可能比较准确”的「翻译」。

    Chapter 2 构造 / 析构 / 赋值

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

    如果你写下:
    class Empty{ };

    事实上编译器会帮你补全:
    class Empty{
    public:
    Empty() { }
    Empty(const Empty& rhs) { }
    ~Empty() { }
    Empty& operator=(const Empty& rhs) { }
    } ;
    这些函数只有被需要时才会被创建出来
    默认构造函数只是单纯的将来源对象每个non-static成员变量拷贝到目标对象


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

    将拷贝构造函数和赋值重载函数显式声明为private吧

    但有一个小缺陷,就是member函数和友元函数依然可以访问,但是会造成连接错误(linkage error)
    编译的话连接器会报错


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

    不作为基类的类不要声明虚析构函数
    有继承关系的基类一定加上virtual析构函数(带多态性质的base class)

    pure virtual纯虚构函数: virtual ~XXX() = 0;


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

    如果客户需要对某个函数运行期间抛出的异常作出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作


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

    若是有两个有继承关系的类,主类有一个virtual函数,并在构造函数里调用;子类定义了另一个版本的此函数,当在main里构造此子类对象时,实际上还是先调用基类的构造函数,然而基类构造函数调用的virtual
    函数版本实际上还是基类的。若此函数会使用子类里的元素,然而之类成员都还未初始化,就会引发错误

    当类中有多个构造函数,它们兴许有共同的部分。有一种较为出色的做法是定义一个void类型的init函数,然后将初始化中需要调用的函数放在里面,将init单独放在构造函数里就好了。

    综上,在构造和析构期间不要调用虚函数,因为这类调用从不下降至derived class


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

    int x,y,z;
    x = y = z = 15;
    根据右结合律,可以解释为x = (y = (z = 15));
    为了实现连锁赋值,赋值操作赋必须返回一个reference指向操作符左侧实参:

    class Widget{
    public:
    	…
    	Widget& operator=(const Widget& rhs){
    		…
    		return *this;
    	}
    };
    

    此标准适用于所有与赋值相关运算


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

    类对象的赋值,看下面一种情况:

    class Widget{
    	…
    private:
    	Bitmap* pb;
    };
    
    Widget& Widget::operator=(const Widget& rhs)
    {
    	delete pb;
    	pb = new Bitmap(*rhs.pb);
    	return *this;
    }
    

    存在的问题是,如果*this和rhs是同一个对象,delete操作会同时删除两者的bitmap。可以这样操作:

    Widget& Widget::operator=(const Widget& rhs)
    {
    	if(this==&rhs) return *this;  //如果是自我赋值则不做任何事
    	delete pb;
    	pb = new Bitmap(*rhs.pb);
    	return *this;
    }
    

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

    如果对于拷贝函数,你的复制成员没有写全,编译器是不会报错的,因为这符合逻辑。所以记得将需要拷贝的成员变量都放进copying函数

    另外,当手动撰写继承类的copying函数时,一定记得在初始化列表复制其base class的成分.否则在复制构造函数中base class成分会由base class的default构造函数初始化,而copy assignment函数根本不会管base class的成分
    可以这样写:(A extends B)
    在copy函数中:

    A::A(const A& rhs):B(rhs)
    {
    	……
    }
    

    在copy assignment函数中:

    A& A::operator=(const A& rhs)
    {
    	if(this==&rhs)
    		return *this;
    	B::operator=(rhs); //对base class成分进行赋值动作
    	……
    	return *this;
    }
    

    现在很清楚了,当你编写一个copying函数,请确保(1)复制所有local成员变量(2)调用所有base classes内适当的copying函数


    OVER

  • 相关阅读:
    ligerui做分页显示数据
    js判断input为空校验
    js操作table倒叙显示序号的问题
    js获取div中的文本框数据
    js数组到后台转 list数组
    table 操作
    js操作table
    父页面调用子页面的方法
    laravel修改密码及与原密码Hash::check比较 阿星小栈
    php获取中文字符拼音首字母 阿星小栈
  • 原文地址:https://www.cnblogs.com/1Kasshole/p/9092847.html
Copyright © 2011-2022 走看看