2011-05-18 23 views
8

Tengo el siguiente código:Pregunta sobre la herencia múltiple en C++?

#include "stdafx.h" 
#include <iostream> 
#include <conio.h> 
using namespace std; 
#define MNAME 30 
class Person { 
public: 
    char name[MNAME + 1]; 
}; 
class Student : public Person { 
}; 
class Staff : public Person { 
}; 
class Faculty : public Student, public Staff { 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    Faculty faculty; 
    cout << "Address of faculty.Person::name: " << &faculty.Person::name << endl; 
    cout << "Address of faculty.Student::name: " << &faculty.Student::name << endl; 
    cout << "Address of faculty.Staff::name: " << &faculty.Staff::name << endl; 

    getch(); 
    return 0; 
} 

Cuando se ejecuta, el programa da los resultados:

Address of faculty.Person::name: 0012FF20 // **Line 1** 
Address of faculty.Student::name: 0012FF20 // **Line 2** 
Address of faculty.Staff::name: 0012FF3F // **Line 3** 

Yo no lo entiendo. ¿Por qué la dirección en Line 1 y Line 2 es diferente de Line 3, mientras que tanto el estudiante como el personal heredan el nombre de la persona?

Respuesta

9

Con la herencia múltiple regular, obtiene múltiples copias de clases base compartidas. Si quiere una copia, use herencia virtual.

explicado bien en Wikipedia

class Student : public virtual Person { 
}; 
class Staff : public virtual Person { 
}; 

Le conseguirá lo que se esperaba

0

class Faculty hereda dos sub objetos de class Person, uno a través de class Student y otro a través de class Staff.

&faculty.Staff::name devuelve la dirección del objeto secundario de class Person derivado a través de class Staff.

&faculty.Student::name devuelve la dirección del objeto secundario de class Person derivado a través de class Student.

Ambos son subobjetos diferentes y, por lo tanto, la dirección diferente.

13

Al hacer herencia múltiple de esta manera se obtienen dos copias de la clase de los abuelos. Este es el problema clásico dreaded diamond, donde se intenta hacer esto:

 

     Person 
    /  \ 
    Student Staff 
     \  /
     Faculty 

sino a través de la herencia normal, que realmente conseguir esto:

 
    Person Person 
     |  | 
    Student Staff 
     \  /
     Faculty 

Así que no hay realmente 2 persona está en una instancia de Facultad, lo que significa interminables obtener 2 nombres

Para obtener el diamante en el primer diagrama de arriba, desea usar virtual inheritance.

class Staff : public virtual Person { 
}; 
class Student : public virtual Person { 
}; 
+0

+1 para la respuesta más detallada. Creo que este debería ser aceptado –

+1

+1 para el arte ASCII. –

0

Por herencia múltiple su clase derivada faculty tiene 2 copias de Person. 1º a Student y 2º a Staff.

Cuando refiere faculty.Person::name, se refiere a través de Student o por Staff. Esta es una situación ambigua e incluso no se compilará con g ++.

En MSVC, parece que ya Faculty hereda Student primero y luego Staff, se está refiriendo faculty.Person::name como facutlty ==> Student ==> Person ==> name. Es por eso que la salida de las primeras 2 líneas es igual y la 3ra línea es diferente.

0

Un poco fuera de tema, pero .... Los desarrolladores más experimentados evitan la herencia múltiple. Es difícil de mantener y lleno de peligros.

+3

Podrías haber proporcionado la información como un comentario :-) – NirmalGeo

1

Has encontrado el clásico problema de herencia de diamantes. Debido a la forma en que la herencia múltiple funciona en C++, en realidad hay dos copias distintas de name en Faculty. Normalmente, esto puede ser resuelto mediante el uso de la herencia virtual de este tipo, por lo que sólo tiene una instancia de Person y sus miembros:

class Student : public virtual Person { 
}; 
class Staff : public virtual Person { 
}; 

Estoy bastante seguro en este caso, sin embargo usted no quiere hacer esto. No parece razonable suponer que cada Faculty es también un Student Y un miembro Staff, por lo que no debe representarlo de esta manera. Parece plausible que un Faculty siempre sea un Staff, por lo que podría usar una herencia única para modelar esa relación. Luego, si es necesario, factorice (en funciones gratuitas o en una clase separada) el código común del alumno que también se necesita en Faculty.