2010-08-22 15 views
11

(perdón la pregunta Noob por adelantado)C++: La herencia múltiple con polimorfismo

tengo 4 clases:

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

Esencialmente Person es la clase base, que son subclases directamente por tanto Student y Employee. StudentEmployee emplea herencia múltiple a la subclase Student y 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}; 

Cuando uso una serie de Person, la clase base, que puede poner Person y todas sus subclases dentro de esta gama. Excepto por StudentEmployee, dada la razón de clase base ambigua.

Dado que StudentEmployee garantiza tener todos los métodos y atributos de Person, ¿es StudentEmployee considerada una subclase de Persona?

  • Si es así, ¿por qué el compilador no me permite asignar un objeto a una variable del tipo de su superclase?
  • Si no, ¿por qué no? y ¿cuál sería la forma correcta de lograr esto?

Saludos


EDIT: preventivamente, esta cuestión no es lo mismo que cualquiera de los siguientes:
polymorphism relates inheritance
Inheritance mucking up polymorphism in C++?

Respuesta

13

StudentEmployee ciertamente es una subclase de Person. El problema es que es tan dos veces: hereda indirectamente Person dos veces (una vez a través de Student y una vez a través de Employee) y es por eso que obtiene el error de "clase base ambigua". Para asegurarse de que sólo se hereda StudentEmployeePerson vez, usted tiene que utilizar la herencia virtual , así:

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

Esto solucionará el error. Sin embargo, hay otro gran problema con su código y se llama slicing.

Al hacer esto:

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

se creará una matriz de tres objetos Person pero esos objetos se copie construyó usando el constructor de copia definido implícitamente de la clase Person. Ahora, el problema con esto es que los objetos de su matriz serán solo objetos Person y no objetos de las subclases que desea que sean.

Para solucionar esto, se tendrá que hacer una matriz de punteros a objetos Person, así:

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

o

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

Pero, obviamente, llamar a un nuevo tipo de ese tipo casi con seguridad generará una pérdida de memoria – Falmarri

+1

+1 para el corte. Y por si acaso bguiz no lo sabía, esto también podría ser Person * ppl [] = {& pat, & sam, & em, &sen }; - hay una ligera diferencia en la administración de la memoria de estas dos opciones. – Michael

+0

@Falmarri: ¿Por qué? Aún tienes la matriz de punteros. – Job

3

Hay dos caminos igualmente posibles a partir de un objeto de escriba StudentEmployee para ser un Person.

Necesita la palabra clave virtual para las clases Student y Employee. Ver FAQ 25.8 De hecho, ve a través de toda esa sección.

+0

Gracias, que en el artículo dado en el clavo en la cabeza ! – bguiz