为什么我的派生类构造函数被删除了?

时间:2016-12-22 08:54:55

标签: c++ constructor copy default

在下面我的编译器说我找不到我的派生类构造函数:

    struct Drink
    {
        Drink(const Drink& other);
    };

    struct PepsiMax : Drink {};

    int main()
    {
        PepsiMax myPepsi;         // <--- the default constructor of PepsiMax cannot be referenced, it is a deleted function
    }

我知道需要定义Drink的默认构造函数,因为我创建了一个复制构造函数,编译器不会为我创建默认构造函数。但是错误消息说它找不到我的PepsiMax类的默认构造函数,我希望它生成。如果我为PepsiMax定义默认构造函数,它会显示一条错误,说它无法找到Drink默认构造函数,这正是我所期望的。

我可以假设它指的是'Drink'的默认构造函数而不是'PepsiMax',或者我是否误解了某些内容?我希望编译器为'PepsiMax'创建一个默认构造函数,它会立即调用基类构造函数。

编辑:感谢你的帮助,我的困惑得到了解决。我对编译器生成的构造函数的天真解释的解释是答案。

4 个答案:

答案 0 :(得分:2)

修复是写

struct Drink
{
    Drink() = default;
    Drink(const Drink& other);
};

复制构造函数的存在避免了自动生成默认构造函数(如您所知)。但是这个也意味着编译器无法生成PepsiMax所依赖的PepsiMax myPepsi; 的默认构造函数。你需要重新介绍它。

答案 1 :(得分:1)

当您尝试创建PepsiMax类型的变量时,应调用该类的默认构造函数。由于它具有基类(Drink),因此该默认构造函数也将调用Drink的默认构造函数。现在,在Drink类中,您已经声明了自己的复制构造函数。这会阻止编译器自动生成默认构造函数,因此无法调用它,因此也无法生成PepsiMax的默认构造函数。

为了防止这种情况,您应该明确告诉编译器使用

生成默认构造函数
Drink() = default;

或为Drink实现您自己的默认构造函数。

答案 2 :(得分:0)

Cppreference引用

  

T的隐式声明或默认默认构造函数是未定义,如果:   T具有直接或虚拟基础,其具有已删除的默认构造函数,或者此构造函数不明确或无法访问。

在您的示例中,由于存在复制构造函数,类Drink的隐式默认构造函数已删除

随后,类PepsiMax的隐式声明或默认默认构造函数未定义,因为它的直接基类Drink具有已删除的默认构造函数。

答案 3 :(得分:0)

我只想补充其他人的答案。我现在明白了,只是想解释一下我的困惑。

struct Base
{
    Base(const Base& other);       // <---- My copy constructor, putting this here prevents the compiler generating a default and empty constructor
};

Derived : Base
{
    // Nothing here. The compiler should generate a default constructor here
    // Something like Derived() : Base::Base() {}
}

现在,有两种方法可以考虑编译器如何为一个天真的人(我)。我的想法是编译器相当于粘贴默认构造函数,然后进行编译。如果这是它实际做的,那么错误消息应该与我手动粘贴该行相同,这实际上是一个不同的错误,它找不到Base默认构造函数,而不是Derived默认构造函数。

但是,“显然”发生的是编译器尝试生成:

Derived() : Base::Base(){}

解析它,找不到Base :: Base(),并且根本不生成该行,然后抱怨它找不到Derived默认构造函数。对于回答的人来说,这是显而易见的这里的混淆是关于编译器如何准确生成默认构造函数。谢谢你给我一点点启发。