La herencia múltiple es una característica de C ++ donde una clase puede heredar de más de una clase.

Los constructores de clases heredadas se llaman en el mismo orden en que se heredan. Por ejemplo, en el siguiente programa, se llama al constructor de B antes que al constructor de A.

#include<iostream>

using namespace std;

 

class A

{

public:

  A()  { cout << "A's constructor called" << endl; }

};

 

class B

{

public:

  B()  { cout << "B's constructor called" << endl; }

};

 

class C: public B, public

{

public:

  C()  { cout << "C's constructor called" << endl; }

};

 

int main()

{

    C c;

    return 0;

}

Producción:

B's constructor called
A's constructor called
C's constructor called

Los destructores se llaman en orden inverso al de los constructores.

El problema del diamante
El problema del diamante ocurre cuando dos superclases de una clase tienen una clase base común. Por ejemplo, en el siguiente diagrama, la clase TA obtiene dos copias de todos los atributos de la clase Person, esto provoca ambigüedades.

Por ejemplo, considere el siguiente programa.

#include<iostream>

using namespace std;

class Person {

   

public:

    Person(int x)  { cout << "Person::Person(int ) called" << endl;   }

};

 

class Faculty : public Person {

   

public:

    Faculty(int x):Person(x)   {

       cout<<"Faculty::Faculty(int ) called"<< endl;

    }

};

 

class Student : public Person {

   

public:

    Student(int x):Person(x) {

        cout<<"Student::Student(int ) called"<< endl;

    }

};

 

class TA : public Faculty, public Student  {

public:

    TA(int x):Student(x), Faculty(x)   {

        cout<<"TA::TA(int ) called"<< endl;

    }

};

 

int main()  {

    TA ta1(30);

}

Person::Person(int ) called
Faculty::Faculty(int ) called
Person::Person(int ) called
Student::Student(int ) called
TA::TA(int ) called

En el programa anterior, el constructor de ‘Persona’ se llama dos veces. El destructor de ‘Person’ también se llamará dos veces cuando se destruya el objeto ‘ta1’. Entonces, el objeto ‘ta1’ tiene dos copias de todos los miembros de ‘Persona’, esto causa ambigüedades. La solución a este problema es la palabra clave ‘virtual’. Hacemos las clases ‘Facultad’ y ‘Estudiante’ como clases base virtuales para evitar dos copias de ‘Persona’ en la clase ‘TA’. Por ejemplo, considere el siguiente programa.

#include<iostream>

using namespace std;

class Person {

public:

    Person(int x)  { cout << "Person::Person(int ) called" << endl;   }

    Person()     { cout << "Person::Person() called" << endl;   }

};

 

class Faculty : virtual public Person {

public:

    Faculty(int x):Person(x)   {

       cout<<"Faculty::Faculty(int ) called"<< endl;

    }

};

 

class Student : virtual public Person {

public:

    Student(int x):Person(x) {

        cout<<"Student::Student(int ) called"<< endl;

    }

};

 

class TA : public Faculty, public Student  {

public:

    TA(int x):Student(x), Faculty(x)   {

        cout<<"TA::TA(int ) called"<< endl;

    }

};

 

int main()  {

    TA ta1(30);

}

Producción:

Person::Person() called
Faculty::Faculty(int ) called
Student::Student(int ) called
TA::TA(int ) called

En el programa anterior, se llama una vez al constructor de ‘Persona’. Una cosa importante a tener en cuenta en el resultado anterior es, el constructor predeterminado de ‘Persona’ se llama. Cuando usamos la palabra clave ‘virtual’, el constructor predeterminado de la clase abuelo se llama por defecto incluso si las clases principales llaman explícitamente al constructor parametrizado.

¿Cómo llamar al constructor parametrizado de la clase ‘Persona’? El constructor debe llamarse en la clase ‘TA’. Por ejemplo, vea el siguiente programa.

#include<iostream>

using namespace std;

class Person {

public:

    Person(int x)  { cout << "Person::Person(int ) called" << endl;   }

    Person()     { cout << "Person::Person() called" << endl;   }

};

 

class Faculty : virtual public Person {

public:

    Faculty(int x):Person(x)   {

       cout<<"Faculty::Faculty(int ) called"<< endl;

    }

};

 

class Student : virtual public Person {

public:

    Student(int x):Person(x) {

        cout<<"Student::Student(int ) called"<< endl;

    }

};

 

class TA : public Faculty, public Student  {

public:

    TA(int x):Student(x), Faculty(x), Person(x)   {

        cout<<"TA::TA(int ) called"<< endl;

    }

};

 

int main()  {

    TA ta1(30);

}

Producción:

Person::Person(int ) called
Faculty::Faculty(int ) called
Student::Student(int ) called
TA::TA(int ) called

En general, no está permitido llamar directamente al constructor del abuelo, debe llamarse a través de la clase padre. Solo está permitido cuando se utiliza la palabra clave ‘virtual’.

Como ejercicio, predice el resultado de los siguientes programas.

Pregunta 1

#include<iostream>

using namespace std;

 

class A

{

  int x;

public:

  void setX(int i) {x = i;}

  void print() { cout << x; }

};

 

class B:  public A

{

public:

  B()  { setX(10); }

};

 

class C:  public A  

{

public:

  C()  { setX(20); }

};

 

class D: public B, public C {

};

 

int main()

{

    D d;

    d.print();

    return 0;

}

Pregunta 2

#include<iostream>

using namespace std;

 

class A

{

  int x;

public:

  A(int i) { x = i; }

  void print() { cout << x; }

};

 

class B: virtual public A

{

public:

  B():A(10) {  }

};

 

class C:  virtual public

{

public:

  C():A(10) {  }

};

 

class D: public B, public C {

};

 

int main()

{

    D d;

    d.print();

    return 0;

}

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema discutido anteriormente.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *