[OOP] Đa kế thừa (multiple inheritance) – Diamond problem

Trong C++ cung cấp cho ta khả năng đa kế thừa, nghĩa là 1 class con có thể kế thừa từ nhiều class cha.

Ví dụ:


#include <iostream>

#include <string>

using namespace std;

class Person

{

private:

   string name;

   int age;

public:

   Person(string name, int age)

   {

      this->name = name;

      this->age = age;

   }

   string GetName() { return name; }

   int GetAge() { return age; }

};

class Employee

{

private:

   string empID;

   double salary;

public:

   Employee(string id, double salary)

   {

      this->empID = id;

      this->salary = salary;

   }

   string GetId() { return empID; }

   double GetSalary() { return salary; }

};

//Class teacher kế thừa từ Person và Employee
class Teacher : public Person, public Employee

{

public:

   Teacher(string name, int age, string id, double salary)
      : Person(name, age), Employee(id, salary)
   
   {
      
      //Initial
   
   }

   friend ostream& operator<<(ostream& out, Teacher& tc)

   {

      out << "Name : " << tc.GetName() << endl;

      out << "Age : " << tc.GetAge() << endl;

      out << "Id : " << tc.GetId() << endl;

      out << "Salary : " << tc.GetSalary() << endl;

      return out;

   }
};

int main()

{

   Teacher tc("Noname", 25, "123456", 1000);

   cout << tc;

   return 0;

}

Kết quả:

Name : Noname
Age : 25
Id : 123456
Salary : 1000

Các vấn đề khi đa kế thừa

1. Các base class có hàm cùng tên, cùng tham số.

Ví dụ:


#include <iostream>

#include <string>

using namespace std;

class Person

{

public:

   void Info()

   {

      cout << "This is class Person" << endl;

   }

};

class Employee

{

public:

   void Info()

   {

      cout << "This is class Person" << endl;

   }

};

//Class teacher kế thừa từ Person và Employee
class Teacher : public Person, public Employee

{

   //TODO

};

int main()

{

   Teacher tc;

   //Hàm info nào sẽ được gọi?
   tc.Info();

   return 0;

}

Ta cũng có thể giải quyết vấn đề này bằng cách chỉ rõ hàm info của class nào.

int main()

{
   
   Teacher tc;
   
   tc.Person::Info();
   
   return 0;

}

2. Khi 2 class cha cùng kế thừa từ 1 base class (Diamond problem).


#include <iostream>

using namespace std;

class Base

{

public:

   void BaseInfo()

   {

      cout << "This is base class" << endl;

   }

};

class Base1 : public Base

{

public:

   void Base1Info()

   {

      cout << "This is base1 class" << endl;

   }

};

class Base2 :  public Base

{

public:

   void Base2Info()

   {

      cout << "This is base2 class" << endl;

   }
};

class Child : public Base1,public Base2

{

public:

   void ChildInfo()

   {

      cout << "This is Child class" << endl;

   }

};

int main()

{

   Child c;

   c.BaseInfo();

   return 0;

}

Khi đó trình biên dịch sẽ thông báo lỗi.

"Child::BaseInfo" is ambiguous.

Vì trình biên dịch không thể xác định được gọi hàm BaseInfo của class nào, vì cả 2 class Base1Base2 đều kế thừa từ Base class. Đây được gọi là “Diamond problem“.

Để giải quyết vấn đề này ta có thể thực hiện.

C1: Xác định rõ hàm BaseInfo của class nào


Child c;

//Gọi hàm BaseInfo của class Base1
c.Base1::BaseInfo();

//Gọi hàm BaseInfo của class Base2
c.Base2::BaseInfo();

C2 : Sử dụng virtual của kế thừa

class Base1 : virtual public Base
{
   //TODO
};

class Base2 : virtual public Base
{
   //TODO
};

class Child : public Base1,public Base2
{
   //TODO
};

Có nên sử dụng đa kế thừa ?

Đa số các ngôn ngữ lập trình bậc cao như C#, java… đều không còn hỗ trợ đa kế thừa (chỉ cho phép implement nhiều interface), có lẽ do những vấn đề mà đa kế thừa mang lại nhiều hơn là lợi ích của nó.

Trong nhiều ngữ cảnh có thể đa kế thừa sẽ là giải pháp tốt và hữu dụng. Tuy nhiên ta cũng nên tránh sử dụng đa kế thừa nếu những giải pháp thay thế nó không quá phức tạp.

Was this article helpful?

Leave A Comment?