Comment passer le résultat de la méthode en tant que paramètre au constructeur de la classe de base en C ++?

J’ai essayé de réaliser quelque chose comme ça:

class Base { public: Base(ssortingng S) { ... }; } class Derived: Base { public: int foo; ssortingng bar() { return ssortingngof(foo); // actually, something more complex }; Derived(int f) : foo(f), Base(bar()) { }; } 

Maintenant, cela ne fonctionne pas comme je veux, car bar () est appelé dans le constructeur Derived avant que foo ne soit initialisé.

J’ai envisagé d’append une fonction statique similaire à bar (), qui prend foo en tant que paramètre, et de l’utiliser dans la liste d’initialisation, mais je me demandais si d’autres techniques pouvaient être utilisées pour sortir de celle-ci. ..

Edit : Merci pour les commentaires – voici comment j’allais gérer la fonction statique. Vous ne savez pas si la surcharge entre une fonction statique et non statique est trop intelligente, mais …

 class Derived: Base { public: int foo; static ssortingng bar(int f) { return ssortingngof(f); // actually, something more complex } ssortingng bar() { return bar(foo); }; Derived(int f) : Base(bar(f)) , foo(f) { }; } 

Oui, utiliser une fonction (méthode de classe statique ou fonction régulière) qui prend foo en paramètre et renvoie une chaîne est une bonne solution. Vous pouvez appeler cette même fonction depuis Derived :: bar pour éviter la duplication de code. Donc, votre constructeur ressemblerait à ceci:

 Derived(int f) : Base(ssortingngof(f)), foo(f) {} 

Je place l’appel au constructeur de base en premier dans la liste pour mettre en évidence l’ordre dans lequel les initialisations se produisent. L’ordre de la liste d’initialisation n’a aucun effet, car tous les membres de la classe sont initialisés dans l’ordre dans lequel ils sont déclarés dans le corps de la classe.

C’est une approche très propre et fonctionnelle du problème. Toutefois, si vous souhaitez toujours peser les alternatives, envisagez d’utiliser la composition au lieu de l’inheritance pour la relation entre les classes dérivée et base:

 class Base { public: Base(ssortingng S) { ... } void bat() { ... } }; class Derived { Base *base; int foo; public: Derived(int f) : base(NULL), foo(f) { base = new Base(bar()); } ~Derived() { delete base; } ssortingng bar() { return ssortingngof(foo); // actually, something more complex } void bat() { base->bat(); } }; 

Vous devrez examiner les avantages et les inconvénients de votre situation particulière. Avec Derived contenant une référence à Base, vous obtenez un meilleur contrôle de l’ordre d’initialisation.

Vous pouvez uniquement appeler des fonctions statiques dans la liste d’initialisation. La façon dont vous l’avez dans votre code:

 class Derived: Base { public: int foo; ssortingng bar() { return ssortingngof(foo); // actually, something more complex }; Derived(int f) : foo(f), Base(bar()) { }; } 

Toujours initialiser la base d’abord, puis foo. L’ordre dans lequel vous écrivez des choses dans une liste d’initialisation de constructeur n’a aucune importance. Il construira toujours dans cet ordre:

  1. Tout d’abord, toutes les classes de base virtuelles
  2. Ensuite, les classes de base non virtuelles dans l’ordre dans lequel elles apparaissent dans la liste des classes de base
  3. Ensuite, tous les objects membres dans l’ordre dans lequel ils ont été définis dans la définition de la classe.

Ainsi, vous appelez ssortingngof avec une valeur non initialisée. Ce problème est résolu dans boost::base_from_member . Notez également que l’appel de toute fonction membre non statique avant tous les initialiseurs de constructeur de toutes les classes de base terminées constitue un comportement indéfini.

Appeler des fonctions statiques est cependant tout à fait correct:

 class Derived: Base { public: int foo; static ssortingng bar(int f) { return ssortingngof(f); // actually, something more complex }; Derived(int f) : Base(bar(f)), foo(f) { }; } 

Le constructeur de la classe de base est toujours appelé avant d’initialiser les autres membres de la classe dérivée; votre compilateur devrait vous avertir que les initialiseurs sont dans le mauvais ordre. La seule solution correcte est de faire de bar() une méthode statique qui prend f comme paramètre.

Le constructeur est pour, eh bien, construire l’object. Cela signifie que, jusqu’à ce qu’il revienne, il n’y a pas d’object là-bas et que les fonctions de membre appelant ne fonctionneront donc pas de manière fiable. Comme tout le monde le dit, utilisez une fonction statique ou une fonction non membre.

J’avais envie de faire ça aussi, mais j’ai fini par abandonner.
Tout appel de fonction approprié peut être utilisé comme paramètre de Base ().
Une autre option consiste à append un constructeur alternatif à Base qui prend un int et effectue la conversion en “chaîne”.

Déplacez simplement votre code constructeur vers une fonction Initialize () et appelez-le depuis le constructeur. C’est beaucoup plus simple que de passer outre à une méthode statique / non statique.