6
votes

Pourquoi les constructeurs C ++ ne sont-ils pas hérités?

Pourquoi le constructeur de passage de l'enfant est-il nécessaire dans ce code? Je penserais que ce ne serait pas, mais le compilateur (GCC et VS2010) se plaint lorsque je l'enlève. Y a-t-il une solution de contournement élégante? Il semble que cela semble inutile de devoir insérer cette cale dans des classes d'enfants.

class Parent
{
public:
  Parent(int i) { }
};

class Child : public Parent
{
public:
  Child(int i) : Parent(i) { }
};

int main()
{
  Child child(4);
  return 0;
}


3 commentaires

Oui, il semble logique sur un exemple aussi simple. Mais dans des exemples plus complexes, je ne veux pas que le compilateur commence à générer automatiquement de nouveaux constructeurs simplement parce qu'il pense que c'est une bonne idée; Cela peut conduire à toutes sortes de conversions auto inattendues où je ne les attends pas.


Bjarne Stroustrop dit ( lien ), "en C ++ 98, nous pouvons «soulever» un ensemble de fonctions surchargées d'une classe de base dans une classe dérivée ... J'ai dit que «peu plus qu'un accident historique empêche de l'utiliser pour travailler pour un constructeur ainsi que pour un ordinateur ordinaire. fonction membre. C ++ 0x fournit cette installation ... "Il se réfère à la relève à l'aide de , par exemple, à l'aide de parent :: parent; , mais je me demande si le manque de constructeur L'héritage en général est également due à des raisons historiques arbitraires.


Oui C ++ 0x a fourni une fonctionnalité supplémentaire. Mais il est pas automatique Vous devez explicitement indiquer que vous le souhaitez. Ce que vous voulez, c'est tout automatisé et c'est une idée Bad car elle conduira à conversions de type auto que vous n'êtes pas en attente. Je crois que c'était envisagé (c'est pourquoi C ++ 0x vous permet d'importer avec à l'aide de parent :: parent; ), mais votre idée a été rejetée (mais je n'ai pas de devis).


7 Réponses :


5
votes

Si vous ne spécifiez pas quel constructeur parent doit être appelé explicitement, le compilateur générera du code qui appelle la valeur par défaut (no-argument ou avec toutes les valeurs par défaut) Constructeur.

Dans votre cas, la classe Parent n'a pas un tel constructeur, le compilateur ne saurait pas quelle valeur à utiliser pour i .

Ne pas spécifier un constructeur en classe enfant signifie que le constructeur par défaut dans la classe parent serait appelé mais cela n'existe pas.


Je ne l'ai pas essayé mais jetez un coup d'œil à Ceci Section de la FAQ C ++ 0x . J'ai l'impression que vous demandez est possible dans C ++ 0x.


1 commentaires

Pourquoi le compilateur chercherait-il le constructeur par défaut si je transmettais un argument dans ma référence de constructeur? Ouais, on dirait que l'on peut "soulever" un constructeur parent dans la portée de l'enfant avec C ++ 0x.



13
votes

Parce que ce qui suit est parfaitement valide:

class Parent
{
public:
    Parent(int i) { }
};

class Child : public Parent
{
public:
    Child() : Parent(42) { }
};


4 commentaires

Je sais que les constructeurs sont essentiellement des méthodes statiques et sont donc différentes des méthodes ordinaires, mais j'aimerais que l'héritage du constructeur fonctionne de la même manière que possible. Par exemple, si ma classe n'utilise pas de multiples héritage, il n'existe aucune ambiguïté quant à quel constructeur parent à appeler car il n'y a qu'un seul parent - le même que avec des méthodes régulières.


Mais il y a souvent de bonnes raisons de ne pas vouloir envoyer des constructeurs. Vous proposez d'ajouter une manipulation spéciale pour la génération automatique du constructeur pour un cas de bord particulier, ce qui compliquerait une langue déjà complexe (IMHO).


Mais C ++ transmet automatiquement d'autres méthodes (publiques et protégées). Pourquoi traiter les constructeurs différents des autres méthodes?


@plong: Parce que cela peut conduire à une conversion de type inattendue. J'aime ma conversion de type pour être explicite ou du moins attendue.



0
votes

Le compilateur n'ajoute que le constructeur par défaut, c'est-à-dire le CTR sans paramètres, mais uniquement si vous n'avez pas défini aucun constructeur.

Dans ce cas, vous avez (dans le parent), donc aucune valeur par défaut n'est faite pour vous, plus l'enfant a besoin de cela afin qu'il sache quoi faire avec le paramètre i que vous passez à cela.


0 commentaires

3
votes

C'est parce que dans C ++, vous avez plusieurs héritages. Dans l'exemple suivant, quel constructeur doit être hérité? XXX


2 commentaires

Facile - il devrait être les paramètres de tous les constructeurs parents, dans l'ordre qu'ils sont déclarés. Hypothétiquement parlant bien sûr. Je ne pense tout simplement pas que c'est la bonne réponse.


Mais puisque je n'utilise pas de héritage multiple, il est évident que le constructeur je parle.



0
votes

Les constructeurs doivent être qualifiés explicitement par le constructeur enfant si vous ne voulez pas utiliser la valeur par défaut qui générée par compilateur, appelée constructeur par défaut (celui sans argument). Mais apparemment dans votre cas, vous voulez un constructeur qui accepte un int , vous devez l'appeler explicitement.


1 commentaires

Ouais, je sais, mais je me demandais pourquoi c'est le cas et s'il y a une solitude élégante. Apparemment non.



1
votes

Voici un autre cas

class Parent
{
public:
  Parent(int i) {this.i = i; }
  Parent() {this.i = 0;}
private:
  int i;
};

class Child : public Parent
{
public:
  Child(int i) : { }
};

int main()
{
  Child child(4);
  return 0;
}


4 commentaires

Utilisez les règles de promotion normales en C ++. Pourquoi les constructeurs devraient-ils être traités des méthodes différentes?


Tout d'abord, votre comportement souhaité est pas précisément comment fonctionne des méthodes normales. Si je remplace foo () dans une classe dérivée, il n'appelle pas automatiquement la version de la classe de base de foo () .


Maintenant, il est vrai que si je définis foo (int x) sur une classe de base, cette fonction est disponible sur un objet de classe dérivé tel quel.


La raison en est que la construction est une opération fondamentalement différente que d'appeler une fonction. Il est logique qu'une classe dérivée aurait besoin de plus de paramètres pour se construire qu'une classe de base; Pas tant de calculer sa zone, par exemple.