2010-08-22 14 views
11

(pardonnez la question noob à l'avance)C++: L'héritage multiple avec polymorphisme

J'ai 4 classes:

class Person {}; 
class Student : public Person {}; 
class Employee : public Person {}; 
class StudentEmployee : public Student, public Employee {}; 

Essentiellement Person est la classe de base, qui sont directement sous-classé par les deux Student et Employee. StudentEmployee utilise l'héritage multiple pour sous-classer les deux Student et Employee.

Person pat = Person("Pat"); 
Student sam = Student("Sam"); 
Employee em = Employee("Emily"); 
StudentEmployee sen = StudentEmployee("Sienna"); 


Person ppl[3] = {pat, sam, em}; 
//compile time error: ambiguous base class 
//Person ppl[4] = {pat, sam, em, sen}; 

Lorsque j'utilise un tableau de Person, la classe de base, je peux mettre Person et toutes ses sous-classes dans ce tableau. Sauf pour StudentEmployee, étant donné la raison de classe de base ambiguë.

Étant donné que StudentEmployee est garanti d'avoir toutes les méthodes et les attributs de Person, StudentEmployee est considéré comme une sous-classe de Person?

  • Si oui, pourquoi le compilateur ne me permet-il pas d'affecter un objet à une variable du type de sa superclasse?
  • Sinon, pourquoi pas; et quelle serait la bonne façon d'accomplir cela?

Vive


EDIT: préventivement, cette question est la même que ce soit des éléments suivants:
polymorphism relates inheritance
Inheritance mucking up polymorphism in C++?

Répondre

13

StudentEmployee est certainement une sous-classe de Person. Le problème est qu'il est si deux fois: Il hérite indirectement Person deux fois (une fois par Student et une fois par Employee) et c'est pourquoi vous obtenez l'erreur "classe de base ambigu". Pour vous assurer StudentEmployee seulement une fois Person hérite, vous devez utiliser héritage virtuel, comme ceci:

class Person {}; 
class Student : public virtual Person {}; 
class Employee : public virtual Person {}; 
class StudentEmployee : public Student, public Employee {}; 

Cela va corriger votre erreur.

Il existe un autre gros problème avec votre code, et il est appelé slicing.

Lorsque vous faites ceci:

Person ppl[3] = {pat, sam, em}; 

Un tableau de trois objets Person sera créé, mais ces objets sera construit en utilisant la copie du constructeur de copie implicitement définie de la classe Person. Maintenant, le problème avec ceci est que les objets dans votre tableau seront juste des objets Person et non des objets des sous-classes que vous voulez qu'ils soient.

Pour résoudre ce problème, vous devrez faire un tableau de pointeurs vers des objets Person, comme ceci:

Person* ppl[] = {new Person("Pat"), new Student("Sam"), 
       new Employee("Emily"), new StudentEmployee("Sienna")}; 

ou

Person* ppl[] = {&pat, &sam, &em, &sen}; 
+0

Mais, de toute évidence, appeler nouveau comme cela conduira presque certainement à une fuite de mémoire – Falmarri

+1

+ 1 pour le découpage. Et juste au cas où bguiz ne le savait pas déjà, cela pourrait aussi être Person * ppl [] = {& pat, & sam, & em, &sen }; - il y a une légère différence dans la gestion de la mémoire de ces deux options. – Michael

+0

@Falmarri: Pourquoi? Vous avez toujours le tableau de pointeurs. – Job

3

Il y a deux chemins également possibles d'un objet de tapez StudentEmployee pour être un Person. Vous devez utiliser le mot-clé virtual pour les classes Student et Employee. Voir FAQ 25.8 En fait, parcourez toute cette section.

+0

Merci, cet article mis le doigt sur la tête ! – bguiz