2010-08-22 22 views
11

(przepraszam za pytanie noob wcześniej)C++: Wiele dziedziczenie z polimorfizmem

Mam 4 klasy:

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

Zasadniczo Person jest klasą bazową, które są bezpośrednio podklasy zarówno Student i Employee. StudentEmployee stosuje dziedziczenie wielokrotne do podklasy zarówno Student, jak i 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}; 

Kiedy używać tablicę Person klasa bazowa, mogę umieścić Person i wszystkie jego podklasy wewnątrz tej tablicy. Z wyjątkiem StudentEmployee, biorąc pod uwagę powód niejednoznacznej klasy bazowej.

Zakłada się, że StudentEmployee ma wszystkie metody i atrybuty Person, jest StudentEmployee za podklasę osoby?

  • Jeśli tak, dlaczego kompilator nie pozwala mi przypisać obiektu do zmiennej typu jej nadklasy?
  • Jeśli nie, dlaczego nie; i jaki byłby właściwy sposób, aby to osiągnąć?

zdrowie


Edycja: zapobiegawczo, to te nie jest takie samo jak jedno z następujących:
polymorphism relates inheritance
Inheritance mucking up polymorphism in C++?

Odpowiedz

13

StudentEmployee z pewnością jest podklasą Person. Problem polega na tym, że dwukrotnie jest to : pośrednio dziedziczy po sobie Person (raz przez Student i raz przez) i dlatego pojawia się błąd "niejednoznacznej klasy bazowej". Aby upewnić się, StudentEmployee dziedziczy tylko Person raz, trzeba użyć wirtualny dziedziczenia, tak:

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

To będzie naprawić swój błąd.

Jest jeszcze jeden poważny problem z kodem, który jest nazywany slicing.

Kiedy to zrobić:

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

Tablica trzech Person obiektów zostanie utworzona, ale te obiekty zostaną zbudowane przy użyciu kopii domyślnie zdefiniowany konstruktor kopiujący klasy Person. Problem polega na tym, że obiekty w twojej tablicy będą tylko obiektami podklas, które mają być.

Aby rozwiązać ten problem, musisz zrobić tablicę wskaźników do Person obiektów, takich jak to:

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

lub

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

Ale, oczywiście, dzwonienie w ten sposób prawie na pewno doprowadzi do wycieku pamięci – Falmarri

+1

+1 za krojenie. I na wszelki wypadek, którego bguiz nie znał, może to być także Person * ppl [] = {& pat & sam & em, &sen }; - jest niewielka różnica w zarządzaniu pamięcią tych dwóch opcji. – Michael

+0

@Falmarri: Dlaczego? Nadal masz szereg wskaźników. – Job

3

Istnieją dwa równie możliwe ścieżki przedmiot wpisz StudentEmployee, aby być Person.

Należy użyć słowa kluczowego virtual dla klas Student i Employee. Zobacz FAQ 25.8 Rzeczywiście przejdź przez całą sekcję.

+0

Dziękuję, że artykuł uderzył w sedno ! – bguiz