Je suis nouveau sur c ++. Lorsque j'essaie de compiler le code ci-dessous, j'obtiens cette erreur
constructor for 'child' must explicitly initialize the base class 'parent' which does not have a default constructor child::child(int a) {
voici ma classe
#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[])
{
}
Pourquoi je reçois cette erreur? Comment puis-je le résoudre? Merci d'avance
La classe parente a un constructeur explicite, donc le compilateur n'y ajoutera pas de constructeur implicite "vide". De plus, votre constructeur a un paramètre, donc le compilateur ne peut pas générer d'appel implicite. C'est pourquoi vous devez le faire explicitement.
Par ici:
child::child(int a) : parent(a)
{
}
Lorsque vous initialisez un objet d'une classe dérivée, la partie de classe de base doit être construite en premier. Si vous ne l'initialisez pas vous-même dans le constructeur de la classe dérivée en appelant l'un de ses constructeurs, le compilateur tentera d'utiliser le constructeur par défaut de la classe de base. Dans votre cas, le constructeur par défaut n'est pas défini car vous avez déjà fourni un constructeur personnalisé.
Pour résoudre ce problème, vous devrez soit fournir un constructeur par défaut pour la classe de base, soit simplement appeler son constructeur dans la liste d'initialisation du constructeur de la classe dérivée:
child::child(int a) : parent(a)
{
}
Au risque de répéter le message d'erreur que vous avez obtenu: un constructeur de classe enfant doit invoquer le constructeur de son parent.
Le compilateur ajoutera une invocation automatique du constructeur par défaut (sans argument) du parent. Si le parent n'a pas de constructeur par défaut, vous devez invoquer explicitement l'un des constructeurs qu'il possède par vous-même.
Le compilateur doit appliquer cela pour garantir que la fonctionnalité que la classe enfant a héritée du parent est correctement configurée ... par exemple, en initialisant toutes les variables privées que l'enfant a héritées du parent, mais auxquelles il ne peut pas accéder directement. Même si votre classe n'a pas ce problème, vous devez toujours suivre les règles.
Voici quelques exemples de constructeurs dans les classes utilisant l'héritage:
C'est très bien, ParentA a un constructeur par défaut:
class ParentA
{
};
class ChildA
{
public:
ChildA() {}
};
Ce n'est pas bien; ParentB n'a pas de constructeur par défaut, donc la classe ChildB1 doit appeler explicitement l'un des constructeurs lui-même:
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) {}
};
C'est bien, nous appelons explicitement le constructeur de ParentB:
class ChildB2 : public ParentB
{
float m_b;
public:
ChildB2(int a, float b) : ParentB(a), m_b(b) {}
};
C'est très bien, ParentC a un constructeur par défaut qui sera appelé automatiquement:
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) {}
};
Un autre exemple où une classe MyBook est dérivée de la classe de base Book. Désormais, un constructeur personnalisé avec deux arguments est fourni pour le constructeur de la classe de base, il n'y a donc pas de constructeur par défaut pour la classe de base. Quand à l'intérieur de la fonction principale, un roman dérivé d'objet de classe est créé, au début le compilateur tentera d'appeler le constructeur de classe de base qui n'existe pas. Ainsi, le constructeur de la classe de base doit être explicitement appelé à partir du constructeur de la classe dérivée pour initialiser toutes les variables privées que la classe dérivée a héritées de la classe de base mais ne peuvent pas accéder directement (par exemple, variable de chaîne de titre). En tant qu'utilisateur tour mentionné, nous devons suivre ces règles. Vous pouvez obtenir des informations plus détaillées à partir de l'explication de Nice de Listes d'initialisation par Alex Allain . Ainsi, les listes d'initialisation sont obligatoires lorsqu'il n'y a pas de constructeur dafault défini et également pour l'initialisation des membres constants. Il résume-
Avant l'exécution du corps du constructeur, tous les constructeurs de sa classe parente puis de ses champs sont appelés. Par défaut, les constructeurs sans argument sont appelés. Les listes d'initialisation vous permettent de choisir quel constructeur est appelé et quels arguments ce constructeur reçoit.
#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;
}