防止在复制构造函数中隐式调用基构造函数

Preventing implicit call to base constructor within copy constructor

本文关键字:构造函数 调用 复制      更新时间:2023-10-16

我想阻止默认构造函数的调用,因此我可以强制用户使用专用构造函数。为此,我只需删除默认构造函数。

当我想为派生类创建复制构造函数时,会出现一个问题。派生类的复制构造函数似乎对父默认构造函数(已删除(进行了隐式调用。编译器不喜欢这样!

有没有办法绕过这个隐式调用?

#include <iostream>
class Base
{
public:
Base() = delete;
Base(int x)
: _x(x)
{
std::cout << "Base's constructor" << std::endl;
}
Base(const Base &other)
{
std::cout << "Base's copy constructor" << std::endl;
this->_x = other._x;
}
protected:
int _x;
};
class Derived : public Base
{
public:
Derived() = delete;
Derived(int x, int y)
: Base(x),  _y(y)
{
std::cout << "Derived's constructor" << std::endl;
}
Derived(const Derived &other)
{
// Implict call to Base(), which is deleted, and compilation fails.
std::cout << "Derived's copy constructor" << std::endl;
this->_x = other._x;
this->_y = other._y;
}
protected:
int _y;
};
int main(int argc, char** argv)
{
Derived d(10,10);
Derived d2(d);
}

你的问题是,由于所有构造函数在进入构造函数的主体之前初始化了它们的所有成员

Derived(const Derived &other)
{
// Implict call to Base(), which is deleted, and compilation fails.
std::cout << "Derived's copy constructor" << std::endl;
this->_x = other._x;
this->_y = other._y;
}

其实是

Derived(const Derived &other) : Base(), _y()
{
// Implict call to Base(), which is deleted, and compilation fails.
std::cout << "Derived's copy constructor" << std::endl;
this->_x = other._x;
this->_y = other._y;
}

其中Base()调用基类默认构造函数。

您需要做的是利用成员初始值设定项列表来调用基类复制构造函数,而不是默认构造函数。 为此,您可以使用

Derived(const Derived &other) : Base(other), _y(other._y)
{
// Implict call to Base(), which is deleted, and compilation fails.
std::cout << "Derived's copy constructor" << std::endl;
// this->_x = other._x; no longer needed as Base(other) takes care of _x
// this->_y = other._y; no longer needed as _y(other._y) takes care of _y
}

您还应该将Base的复制构造函数更新为

Base(const Base &other) : _x(other._x)
{
std::cout << "Base's copy constructor" << std::endl;
}

您还应该注意,您可以在不定义任何这些复制构造函数的情况下逃脱。 由于尚未定义析构函数,编译器将为这两个类自动生成复制构造函数,并且这些默认复制构造函数将正常工作。

不需要使用=delete来阻止调用默认构造函数。您可以使用以前的技术将其声明为private。当然,在这种情况下,由于您希望派生类可以访问它,因此应改为将其设置为protected

但您也可以显式构造所需的基类:

Derived(const Derived &other)
: Base(other._x)
, _y(other._y)
{
std::cout << "Derived's copy constructor" << std::endl;
}