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

Posted

技术标签:

【中文标题】为啥我的派生类构造函数被删除了?【英文标题】:Why is my derived class constructor deleted?为什么我的派生类构造函数被删除了? 【发布时间】:2016-12-22 08:54:54 【问题描述】:

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

    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”创建一个默认构造函数,它首先会立即调用基类构造函数。

编辑:我的困惑已经解决,感谢您的帮助。我对编译器生成的构造函数的天真解释的解释在答案中。

【问题讨论】:

这是因为Drink没有默认构造函数,只有你刚刚指定的复制构造函数Drink::Drink(const Drink &)。如果需要默认构造函数,请在结构 Drink 中添加 Drink() 或在结构 PepsiMax 中添加 PepsiMax()。 【参考方案1】:

解决办法是写

struct Drink

    Drink() = default;
    Drink(const Drink& other);
;

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

【讨论】:

“复制构造函数的存在删除了默认构造函数。” 这似乎是一种误导性的说法,因为deletes the default constructor 可以说自 C+ 以来具有特定含义+11。 @Nawaz:确实你是对的。我玩过这些术语。 @Bathsheba Drink 的复制构造函数意味着编译器不会自动生成 DRINK 的默认构造函数,对吧?但是看到好像我没有为 PepsiMax 定义任何构造函数,它应该自动生成 PepsiMax 的默认构造函数,我会想的。错误说它找不到 PepsiMax 构造函数。 但它不能自动生成默认构造函数,因为缺少Drink 默认构造函数。这就是我在回答中想要表达的意思。 @Bathsheba 为什么默认 PepsiMax 构造函数的自动生成依赖于 Drink 默认构造函数?我认为当我创建 PepsiMax 对象时,首先调用 PepsiMax 构造函数,然后调用基类构造函数。抱歉,我没听懂。【参考方案2】:

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

为了防止这种情况,你应该明确告诉编译器生成一个默认构造函数

Drink() = default;

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

【讨论】:

但是为 Drink 定义一个复制构造函数会阻止编译器为 Drink 自动生成一个默认构造函数。我没有为 PepsiMax 定义任何构造函数,所以我希望生成它的默认构造函数。但是错误消息是它找不到 PepsiMax 的默认构造函数,而不是 Drink。 @TitoneMaurice,无法生成 PepsiMax 的默认构造函数 - 格式错误,因为它需要调用不存在的 Drink 的默认构造函数。【参考方案3】:

Cppreference 引号 那个

T的隐式声明或默认的默认构造函数是undefined,如果: T 有一个直接的或虚拟的基础,它有一个已删除的默认构造函数,或者它不明确或无法从此构造函数访问。

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

随后,类PepsiMax 的隐式声明或默认默认构造函数未定义,考虑到其直接基类Drink 已删除默认构造函数。

【讨论】:

【参考方案4】:

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

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 默认构造函数。这对于那些回答的人来说是显而易见的。这里的困惑在于编译器“如何”准确地生成默认构造函数。感谢您对我的启发。

【讨论】:

以上是关于为啥我的派生类构造函数被删除了?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在基类构造函数中看不到派生类属性值?

请问含有多个对象成员的派生类的构造函数执行时不是先执行基类么?为啥这个先输出的是“正式生是”这个

C++基类和派生类的构造函数

为啥不能在派生类的构造函数初始化列表中初始化基类的数据成员?

与默认构造函数有关,CMFCPropertyGridProperty的派生类构造函数怎么写

C++如何使用派生类构造函数销毁基类中的对象