Cette question a été rencontrée lors de la lecture de this section on learncpp.com. J'ai utilisé le code listé ici, puis j'ai fait de légères modifications pour les tests.Appel de constructeurs pendant l'héritage virtuel avec C++
Contexte
L'héritage virtuel crée une référence commune à la classe de base, ce qui a deux effets. Tout d'abord, il supprime l'ambiguïté car une seule copie des membres de la base est créée (par exemple, ajouter une fonction print() à PoweredDevice et l'appeler dans main() provoquerait sinon une erreur de compilation). Deuxièmement, la classe la plus dérivée devient responsable de l'appel du constructeur de base. Si l'une des classes intermédiaires tente d'invoquer le constructeur de base dans une liste d'initialisation, l'appel doit être ignored.
Le problème
Quand je compiler et exécuter le code, il retourne:
PoweredDevice: 3
PoweredDevice: 3
Scanner: 1
PoweredDevice: 3
Printer: 2
Il devrait retourner:
PoweredDevice: 3
Scanner: 1
Printer: 2
Quand je suis l'exécution en utilisant GDB (7,11 .1), il montre que les fonctions intermédiaires appellent aussi PoweredDevice via la liste d'initialisation - mais celles-ci doivent être ignorées. Cette initialisation multiple de PoweredDevice ne conduit pas à l'ambiguïté des membres, mais me perturbe car le code s'exécute plusieurs fois quand il ne devrait arriver qu'une seule fois. Pour un problème plus compliqué, je ne serais pas à l'aise avec l'héritage virtuel.
Pourquoi ces classes intermédiaires initialisent-elles toujours la base? Est-ce une bizarrerie avec mon compilateur (gcc 5.4.0) ou est-ce que je ne comprends pas comment l'héritage virtuel fonctionne?
Modifier: Code
#include <iostream>
using namespace std;
class PoweredDevice
{
public:
int m_nPower;
public:
PoweredDevice(int nPower)
:m_nPower {nPower}
{
cout << "PoweredDevice: "<<nPower<<endl;
}
void print() { cout<<"Print m_nPower: "<<m_nPower<<endl; }
};
class Scanner : public virtual PoweredDevice
{
public:
Scanner(int nScanner, int nPower)
: PoweredDevice(nPower)
{
cout<<"Scanner: "<<nScanner<<endl;
}
};
class Printer : public virtual PoweredDevice
{
public:
Printer(int nPrinter, int nPower)
: PoweredDevice(nPower)
{
cout<<"Printer: "<<nPrinter<<endl;
}
};
class Copier : public Scanner, public Printer
{
public:
Copier(int nScanner, int nPrinter, int nPower)
:Scanner {nScanner, nPower}, Printer {nPrinter, nPower}, PoweredDevice {nPower}
{ }
};
int main()
{
Copier cCopier {1,2,3};
cCopier.print();
cout<<cCopier.m_nPower<<'\n';
return 0;
}
quelles "légères altérations" avez-vous faites? De toute façon vous devriez poster le code ici – user463035818
Bienvenue sur Stack Overflow! S'il vous plaît ** [edit] ** votre question avec un [mcve] ou [SSCCE (court, autonome, exemple correct)] (http://sscce.org) – NathanOliver
Ajout du code dans une édition.Les variations que j'ai vérifiées incluaient les valeurs et fonctions des membres dans la classe de base, y compris les différents spécificateurs d'accès. J'ai également essayé de changer les niveaux d'accès à l'héritage virtuel. –