Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C++

Kế thừa đa thừa (Multiple Inheritance) trong C++

Multiple Inheritance: Một class dẫn xuất từ nhiều base class. Kế thừa tính năng từ nhiều nguồn.

Cú pháp

class Derived : public Base1, public Base2, ... {
    // members
};

Ví dụ cơ bản

#include <iostream>
using namespace std;

class A {
public:
    int a = 5;
    A() { cout << "Constructor A\n"; }
};

class B {
public:
    int b = 10;
    B() { cout << "Constructor B\n"; }
};

class C : public A, public B { // Kế thừa cả A và B
public:
    int c = 20;
    C() { cout << "Constructor C\n"; }
};

int main() {
    C obj;
    cout << "a = " << obj.a << ", b = " << obj.b << ", c = " << obj.c << '\n';
    return 0;
}

Kết quả

Constructor A
Constructor B
Constructor C
a = 5, b = 10, c = 20

Thứ tự khởi tạo/hủy

  1. Base classes: theo thứ tự khai báo trong class C : public A, public B (A trước, B sau)
  2. Member variables: theo thứ tự khai báo trong class
  3. Derived constructor body
  4. Hủy: ngược thứ tự (Derived → Member → Base B → Base A)

Vấn đề: Diamond Problem (Vấn đề kim cương)

      Base
     /    \
   Derived1 Derived2
     \    /
      Final

Nếu không dùng virtual inheritance → Final có 2 bản sao Base → ambiguity.

Giải pháp: Virtual Inheritance

class Base {
public:
    int value = 42;
};

class Derived1 : virtual public Base {}; // Virtual
class Derived2 : virtual public Base {}; // Virtual

class Final : public Derived1, public Derived2 {
public:
    void show() { cout << value; } // OK: chỉ 1 Base subobject
};

So sánh

Best Practices

  • Tránh multiple inheritance nếu có thể (composition > inheritance)
  • Nếu cần: Chỉ kế thừa từ một class có state, các class khác nên là pure interface (chỉ pure virtual functions)
  • Dùng virtual inheritance cho diamond
  • Sử dụng using Base::func để resolve name hiding
  • C++17: [[no_unique_address]] cho empty base optimization

Ví dụ Interface + Implementation

class ISerializable { // Interface
public:
    virtual std::string serialize() const = 0;
    virtual ~ISerializable() = default;
};

class ILoggable { // Interface
public:
    virtual void log() const = 0;
    virtual ~ILoggable() = default;
};

class User : public ISerializable, public ILoggable { // OK: multiple interface
    std::string name;
public:
    std::string serialize() const override { return "User:" + name; }
    void log() const override { std::cout << "Log: " << name; }
};
Kế thừa thườngVirtual Inheritance
Mỗi path tạo 1 base subobjectChỉ 1 base subobject chung
Gây ambiguity nếu diamondGiải quyết ambiguity
Layout đơn giảnPhức tạp (vptr/vtable thêm)
Hiệu năngTruy cập trực tiếpIndirect (thường qua vptr)