Sha*_*oya 6 c++ inheritance stl multiple-inheritance copy-constructor
考虑一下这段代码:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我系统的输出是:
Base destructor: b
Child destructor
Base destructor: c
Base destructor: b
Base destructor: b
Base destructor: c
Run Code Online (Sandbox Code Playgroud)
我的问题是:
为什么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
Run Code Online (Sandbox Code Playgroud)
第1行:矢量v构造
第2行:构造Base b(调用Base的构造函数)
第3行:构造子c(调用Child的构造函数和Base的构造函数)
第4行:v是最大容量的当前值,需要调整大小.
内存分配给Base的1个元素
v.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").
删除Base b(调用Base的析构函数("Base destructor:b")).
Base v [0], v [1]被删除(调用Base的析构函数两次("Base析构函数:b","Base析构函数:c")).
没有内存泄漏 - 对于上面序列中的每个构造函数,都会调用相应的析构函数.
此外,您似乎对复制构造函数非常困惑.子c被传递给push_back作为Base& - 然后按预期调用Base的复制构造函数.由于Base的隐式复制构造函数不是虚拟的或覆盖的,因此让Child从uncopyable派生不会改变它.
注意,a vector<Base>不能存储Child类型的对象; 它只知道为Base分配足够的内存.将Child实例分配给Base时发生的事情称为切片,虽然通常是无意识和误解,但在您描述的场景中看起来可能实际上是您想要的.
| 归档时间: |
|
| 查看次数: |
1635 次 |
| 最近记录: |