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

时间:2018-10-16 17:43:37

标签: c++ copy-constructor

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

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

有没有办法解决这个隐式调用?

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

2 个答案:

答案 0 :(得分:4)

您的问题是,由于所有构造函数在输入构造函数的主体之前都会初始化其所有成员

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

您还应该注意,无需定义任何副本构造函数就可以摆脱困境。由于您尚未定义析构函数,因此编译器将自动为这两个类生成副本构造函数,而这些默认副本构造函数将正常工作。

答案 1 :(得分:1)

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

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

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