错误:基类构造函数必须显式初始化父类构造函数

46

我是C++的新手。当我尝试编译下面的代码时,我遇到了这个错误:

constructor for 'child' must explicitly initialize the base class 'parent' which does not have a default constructor child::child(int a) {

这是我的类:

#include<iostream>
using namespace std;

class Parent
{   
public :
    int x;
    Parent(int a);
    int getX();
};
Parent::Parent(int a)
{
    x = a;
}
int Parent::getX() 
{
    return x;
}
class Child : public Parent
{
public:
    Child(int a);   
};
Child::Child(int a) 
{
    x = a;
}
int main(int n , char *argv[]) 
{

}

我为什么会收到这个错误信息? 该如何解决? 提前致谢。

5个回答

57

父类具有显式构造函数,因此编译器不会为其添加隐式的“空”构造函数。此外,您的构造函数具有参数,因此编译器无法生成对它的隐式调用。这就是为什么您必须明确地调用它。

做法如下:

 child::child(int a) : parent(a)
 {
 }

20

在初始化派生类对象时,必须先构造基类部分。如果你没有在派生类构造函数中调用其中一个构造函数来自己初始化基类,编译器会试图使用基类的默认构造函数。在你的情况下,因为你已经提供了自定义构造函数,所以默认构造函数未定义。

要解决这个问题,你可以为基类提供一个默认构造函数,或者在派生类构造函数的初始化列表中简单地调用其构造函数:

child::child(int a) : parent(a)
 {
 }

7
冒着重复您得到的错误信息的风险,子类构造函数必须调用其父类的构造函数。
编译器将自动调用父类的默认(无参数)构造函数。如果父类没有默认构造函数,则必须自己显式地调用其中一个它具有的构造函数。
编译器必须执行此操作,以确保从父类继承的功能设置正确...例如,初始化子类从父类继承但不能直接访问的任何私有变量。即使您的类没有这个问题,您仍必须遵循规则。
以下是使用继承的类中构造函数的一些示例:
这是可以的,ParentA有一个默认构造函数:
class ParentA
{
};

class ChildA
{
public:
    ChildA() {}
};

这不太好;ParentB没有默认构造函数,因此ChildB1类必须显式调用其中一个构造函数:

class ParentB
{
    int m_a;

public:
    ParentB(int a) : m_a(a) {}
};

class ChildB1 : public ParentB
{
    float m_b;

public:
    // You'll get an error like this here:
    // "error: no matching function for call to ‘ParentB::ParentB()’"
    ChildB1 (float b) : m_b(b) {}
};

这很好,我们在显式调用ParentB的构造函数:
class ChildB2 : public ParentB
{
    float m_b;

public:
    ChildB2(int a, float b) : ParentB(a), m_b(b) {}
};

这很好,ParentC有一个默认构造函数,将自动调用:

class ParentC
{
    int m_a;

public:
    ParentC() : m_a(0) {}
    ParentC(int a) : m_a(a) {}
};

class ChildC: public ParentC
{
    float m_b;

public:
    ChildC(float b) : m_b(b) {}
};

5

这是一个例子,其中一个MyBook类从基类Book派生而来。现在为基类构造函数提供了两个自定义参数的构造函数,因此基类没有默认构造函数。当在主函数内创建派生类对象novel时,编译器首先尝试调用不存在的基类构造函数。因此,必须从派生类构造函数中显式调用基类构造函数,以初始化派生类从基类继承但无法直接访问的任何私有变量(例如标题字符串变量)。正如用户rook所提到的,我们需要遵循这些规则。您可以从Alex Allain的详细解释中获得更多信息Initialization Lists。因此,当没有定义默认构造函数并且还要初始化常量成员时,必须使用初始化列表。他总结道-

在运行构造函数主体之前,会先调用其父类的构造函数,然后调用其字段的构造函数。默认情况下,将调用无参构造函数。初始化列表允许您选择调用哪个构造函数以及该构造函数接收哪些参数。
#include <iostream>
#include <cstdio>

using namespace std;

class Book {
private:
    string title;
protected:
    string author;
public:
    Book(string t, string a) {
        title = t;
        author = a;
    };
    virtual void display() = 0;
};

class MyBook : public Book {
private:
        const string className;
protected:
        int price;
public:
        // Book(t,a) needs to be called before the {} block to initialize, otherwise error (does not match to Book::Book() default constructor will occur)         
        MyBook(string t, string a, int p) : Book(t, a), className("MyClass"), price(p){
        };

        void display() {
            cout << "Title: " << getTitle() << endl;
            cout << "Author: " << author << endl;
            cout << "Price: " << price << endl;
        };
};

int main() {
    string title, author;
    int price;
    getline(cin, title);
    getline(cin, author);
    cin >> price;
    MyBook novel(title, author, price);
    novel.display();

    return 0;
}

-5

你好,尝试在你的父类中添加默认构造函数(无参数构造函数),然后编译它。希望这可以解决你的问题。


2
这不是一个好的解决方案,因为它允许您构造一个未定义状态的“parent”实例。如果“parent”是一个无法实例化的抽象类,那么这可能还可以接受,但事实并非如此。 - Rook

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接