Khái niệm lớp cơ sở ảo trong lập trình hướng đối tượng với C++

Đây là bài 19/19 bài của series môn học Lập trình hướng đối tượng

1. Khai báo lớp cơ sở ảo (virtual base class)

Có một vấn đề khi một lớp cơ sở được kế thừa bởi nhiều lớp dẫn xuất. Ví dụ, xét tình huống các lớp kế thừa theo sơ đồ như sau:

Sơ đồ kế thừa với virtual base class in C++

Hai lớp B và C kế thừa từ lớp A. Lớp D kế thừa từ cả hai lớp B và C. Như vậy, lớp A được kế thừa hai lần bởi lớp D. Lần thứ nhất được kế thừa thông qua lớp B, lần thứ hai được kế thừa thông qua lớp C.

Lúc này, nếu đối tượng của lớp D gọi đến một hàm được kế thừa từ lớp A thì sẽ gây ra một sự mơ hồ. Không biết hàm đó được kế thừa gián tiếp từ lớp B hay lớp C.

#include <iostream>
using namespace std;

class A{
public:
    void show(){
        cout << "Hello from A \n";
    }
};
  
class B : public A{
};
  
class C : public A{
};
  
class D : public B, public C{
};

void main(){
	D object;
    object.show();//error: ambiguous access of 'show'
	system("pause");
}
Kết quả
error: ambiguous access of 'show'

Để giải quyết tính không rõ ràng này, C++ có một cơ chế mà nhờ đó chỉ có một bản sao của lớp A ở trong lớp D. Đó là sử dụng lớp cơ sở ảo (virtual base class).

Vẫn lấy ví dụ trên, C++ sử dụng từ khóa vitual để khai báo lớp A là lớp cơ sở ảo trong các lớp B và C theo cú pháp sau:

class A{
//Định nghĩa lớp
};
class B : virtual public A{
//Định nghĩa lớp
};
class C : virtual public A{
//Định nghĩa lớp
};
class D : public B, public C{
//Định nghĩa lớp
};

Việc chỉ định A là lớp cơ sở ảo trong các lớp B và C, nghĩa là A sẽ chỉ xuất hiện một lần trong lớp D. Khai báo này không ảnh hưởng đến các lớp B và C.

Cú pháp 1:
class B : virtual public A{
};

Cú pháp 2:
class B : public virtual A{
};

Lưu ý: Từ khóa virtual có thể đặt trước hoặc sau từ khóa public, private, protected.

#include <iostream>
using namespace std;

class A{
public:
    void show()
    {
        cout << "Hello from A \n";
    }
};
  
class B : virtual public A{//lớp cơ sở ảo
};
  
class C : virtual public A{//lớp cơ sở ảo
};
  
class D : public B, public C{
};

void main(){
	D object;
    object.show();
	system("pause");
}
Kết quả
Hello from A

2. Hàm khởi tạo và hàm hủy đối với lớp cơ sở ảo

Hàm khởi tạo của một lớp cơ sở ảo luôn luôn được gọi trước các hàm khởi tạo khác. Hàm hủy của một lớp cơ sở ảo luôn luôn được gọi sau các hàm hủy khác.

#include <iostream>
using namespace std;

class A{
public:
	A(){
		cout<<"Constructor of A"<<endl;
	}
    ~A(){
		cout<<"Destructor of A"<<endl;
	}
};
  
class B : virtual public A{
public:
	B(){
		cout<<"Constructor of B"<<endl;
	}
	~B(){
		cout<<"Destructor of B"<<endl;
	}
};
  
class C : virtual public A {
public:
	C(){
		cout<<"Constructor of C"<<endl;
	}
	~C(){
		cout<<"Destructor of C"<<endl;
	}
};
  
class D : public B, public C {
public:
	D(){
		cout<<"Constructor of D"<<endl;
	}
	~D(){
		cout<<"Destructor of D"<<endl;
	}
};

void main(){
	D object;
	system("pause");
}
Kết quả
Constructor of A
Constructor of B
Constructor of C
Constructor of D
Destructor of D
Destructor of C
Destructor of B
Destructor of A
5/5 - (1 bình chọn)
Bài trước và bài sau trong môn học<< Khái niệm đa hình (polymorphism) trong lập trình hướng đối tượng
Chia sẻ trên mạng xã hội:

Trả lời

Lưu ý:

1) Vui lòng bình luận bằng tiếng Việt có dấu.

2) Khuyến khích sử dụng tên thật và địa chỉ email chính xác.

3) Mọi bình luận trái quy định sẽ bị xóa bỏ.