微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – 乘法继承类的复制构造函数

考虑一下这段代码
#include <vector>
#include <iostream>
using namespace std;

class Base
{
    char _type;
public:
    Base(char type):
        _type(type)
    {}

    ~Base() {
        cout << "Base destructor: " << _type << endl;
    }
};

class uncopyable
{
    protected:
        uncopyable() {}
        ~uncopyable() {}
    private:
        uncopyable( const uncopyable& );
        const uncopyable& operator=( const uncopyable& );
};

class Child : public Base,private uncopyable
{
    int j;
public:
    Child():
        Base('c')
    {}
    ~Child() {
        cout << "Child destructor" << endl;
    }
};


int main()
{
    vector<Base> v;
    Base b('b');
    Child c;

    v.push_back(b);
    v.push_back(c);
    return 0;
}

我系统的输出是:

Base destructor: b
Child destructor
Base destructor: c
Base destructor: b
Base destructor: b
Base destructor: c

我的问题是:

>为什么Base(具有类型b)的析构函数调用三次而不是两次(我们是否有两个以上的对象b副本)?
>当我们复制Child类型的对象时会发生什么,考虑到其父级之一的copy-constructor是私有的.是不确定的行为?
>每当我尝试复制Child类型的对象时,我都希望得到编译时错误.我认为子的认拷贝构造函数会尝试调用Uncopyable类的私有拷贝构造函数并导致编译错误.为什么不给出编译错误

代码以这种方式设计的原因是因为Child类很大.

每当客户端尝试复制Child对象(调用Child的析构函数而不调用Base的析构函数)时,所需的行为就是丢弃子数据.

这段代码实现了这一点,但我猜它会导致未定义的行为并且有内存泄漏(从不为复制的实例调用Child的析构函数).

解决方法

以下是您的代码中发生的情况:
int main() 
{ 
    vector<Base> v;    // 1
    Base b('b');       // 2
    Child c;           // 3

    v.push_back(b);    // 4
    v.push_back(c);    // 5
    return 0; 
}                      // 6

>第1行:矢量v构造
>第2行:构建Base b(调用Base的构造函数)
>第3行:构造子c(调用Child的构造函数和Base的构造函数)
>第4行:v是最大容量的当前值,需要调整大小.
内存由v分配给Base的1个元素.
Base b复制到v [0](调用Base的复制构造函数).
>第5行:v再次处于最大容量,需要调整大小.
内存由v分配给Base的2个元素.
旧的v [0]被复制到新的v [0]中(调用Base的复制构造函数).
删除旧的v [0](调用Base的析构函数(“Base destructor:b”)).
将子c复制到v [1](调用Base的复制构造函数).
>第6行:c,b和v超出范围.
删除子c(调用Child的析构函数(“Child析构函数”),然后删除Base的析构函数(“Base destructor:c”).
基数b被删除(调用Base的析构函数(“Base析构函数:b”)).
删除Base v [0],v [1](调用Base的析构函数两次(“Base析构函数:b”,“Base析构函数:c”)).

没有内存泄漏 – 对于上面序列中的每个构造函数,都会调用相应的析构函数.

此外,您似乎对复制构造函数非常困惑.子c被传递给push_back作为Base& – 然后按预期调用Base的复制构造函数.由于Base的隐式复制构造函数不是虚拟的或覆盖的,因此让Child从uncopyable派生不会改变它.

注意,矢量< Base>不能存储Child类型的对象;它只知道为Base分配足够的内存.将Child实例分配给Base时发生的事情称为切片,虽然通常是无意识和误解,但在您描述的场景中看起来可能实际上是您想要的.

原文地址:https://www.jb51.cc/c/113096.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐