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

Preventing implicit call to base constructor within copy constructor

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

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

有什么办法绕过这个隐式调用吗?

#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() 调用基础 class 默认构造函数。

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

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;
}

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

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

但是你也可以显式构造需要的基数class:

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