web-dev-qa-db-fra.com

Comment appeler le constructeur de la classe de base?

j'ai passé beaucoup de temps à programmer en Java. Là, vous appelez la classe dont vous avez hérité avec super(); (vous le savez probablement tous)

Maintenant, j'ai une classe en C++ qui a un constructeur par défaut qui prend des arguments. Exemple:

class BaseClass {
public:
    BaseClass(char *name); .... 

Si j'hérite de la classe, cela me donne l'avertissement qu'il n'y a pas de constructeur par défaut approprié disponible. Alors, y a-t-il quelque chose comme super() en C++, ou dois-je définir une fonction pour initialiser toutes les variables?

62
Stefan

Vous faites cela dans la liste initializer du constructeur de la sous-classe.

class Foo : public BaseClass {
public:
    Foo() : BaseClass("asdf") {}
};

Les constructeurs de classe de base qui acceptent des arguments doivent y être appelés avant que leurs membres ne soient initialisés.

81
Björn Pollex

Dans le fichier d'en-tête, définissez une classe de base:

class BaseClass {
public:
    BaseClass(params);
};

Définissez ensuite une classe dérivée comme héritant de BaseClass:

class DerivedClass : public BaseClass {
public:
    DerivedClass(params);
};

Dans le fichier source, définissez le constructeur BaseClass:

BaseClass::BaseClass(params)
{
     //Perform BaseClass initialization
}

Par défaut, le constructeur dérivé appelle uniquement le constructeur de base par défaut sans paramètre. Ainsi, dans cet exemple, le constructeur de la classe de base N'EST PAS appelé automatiquement lorsque le constructeur dérivé est appelé, mais cela peut être obtenu simplement en ajoutant la syntaxe du constructeur de la classe de base après un signe deux-points (:). Définissez un constructeur dérivé qui appelle automatiquement son constructeur de base:

DerivedClass::DerivedClass(params) : BaseClass(params)
{
     //This occurs AFTER BaseClass(params) is called first and can
     //perform additional initialization for the derived class
}

Le constructeur BaseClass est appelé AVANT le constructeur DerivedClass, et les mêmes paramètres/différents paramètres params peuvent être transmis à la classe de base si nécessaire. Cela peut être imbriqué pour des classes dérivées plus profondes. Le constructeur dérivé doit appeler EXACTLY ONE constructeur de base. Les destructeurs sont AUTOMATIQUEMENT appelés dans l'ordre REVERSE auquel les constructeurs ont été appelés.

EDIT: Il existe une exception à cette règle si vous héritez de classes virtual, généralement pour obtenir héritage multiple ou héritage diamond. Ensuite, vous DEVEZ appeler explicitement les constructeurs de base de toutes les classes de base virtual et leur transmettre explicitement les paramètres. Sinon, seuls les constructeurs par défaut seront appelés sans tous les paramètres. Voir: héritage virtuel - constructeurs ignorés

28
MasterHD

Vous devez utiliser les initiailzers:

class DerivedClass : public BaseClass
{
public:
  DerivedClass()
    : BaseClass(<insert arguments here>)
  {
  }
};

C'est également ainsi que vous construisez des membres de votre classe qui n'ont pas de constructeur (ou que vous souhaitez initialiser). Tous les membres non mentionnés seront initialisés par défaut. Par exemple:

class DerivedClass : public BaseClass
{
public:
  DerivedClass()
    : BaseClass(<insert arguments here>)
    , nc(<insert arguments here>)
    //di will be default initialized.
  {
  }

private:
  NeedsConstructor nc;
  CanBeDefaultInit di;
};

L'ordre dans lequel les membres sont spécifiés est sans importance (bien que les constructeurs doivent venir en premier), mais l'ordre dans lequel ils seront construits est dans l'ordre de la déclaration. Donc, nc sera toujours construit avant di.

17
Nicol Bolas

En ce qui concerne l'alternative à super; vous utiliseriez dans la plupart des cas utiliser la classe de base soit dans la liste d'initialisation de la classe dérivée, soit à l'aide de la commande Base::someData syntaxe lorsque vous travaillez ailleurs et que la classe dérivée redéfinit les membres de données.

struct Base
{
    Base(char* name) { }
    virtual ~Base();
    int d;
};

struct Derived : Base
{
    Derived() : Base("someString") { }
    int d;
    void foo() { d = Base::d; }
};
4
Seb Holzapfel

Utilisez le nom de la classe de base dans une liste d'initialisation. La liste d'initialisation apparaît après la signature du constructeur avant le corps de la méthode et peut être utilisée pour initialiser les classes de base et les membres.

class Base
{
public:
  Base(char* name)
  {
     // ...
  }
};

class Derived : Base
{
public:
  Derived()
    : Base("hello")
  {
      // ...
  }
};

Ou encore, un modèle utilisé par certaines personnes consiste à définir vous-même le mot "super" ou "base". Parmi les personnes qui sont en faveur de cette technique, certains sont peut-être les développeurs Java) qui passent au C++.

class Derived : Base
{
public:
  typedef Base super;
  Derived()
    : super("hello")
  {
      // ...
  }
};
3
Scott Langham

Il n'y a pas de super () en C++. Vous devez appeler explicitement le constructeur de base par son nom.

2
Shamim Hafiz