Lớp Trừu tượng và Hàm Ảo Thuần túy
Các lớp trừu tượng được sử dụng để tạo ra các thực thể chung, mà bạn mong muốn sử dụng để tạo ra các lớp dẫn xuất cụ thể hơn. Một lớp trừu tượng chỉ có thể được dùng làm lớp cơ sở cho một lớp khác, đó là lý do tại sao không thể tạo một đối tượng thuộc kiểu lớp trừu tượng.
Một lớp chứa ít nhất một hàm ảo thuần túy được coi là trừu tượng. Do đó, các lớp dẫn xuất từ lớp trừu tượng phải triển khai tất cả các hàm ảo thuần túy của nó, nếu không chúng cũng sẽ là các lớp trừu tượng.
Một hàm ảo được khai báo là "thuần túy" bằng cách sử dụng cú pháp chỉ định thuần túy. Hãy xem xét ví dụ về lớp CAnimal, được tạo ra chỉ để cung cấp các hàm chung – các đối tượng kiểu CAnimal quá chung chung để sử dụng thực tế. Do đó, CAnimal là một ví dụ tốt cho lớp trừu tượng:
class CAnimal
{
public:
CAnimal(); // Hàm tạo
virtual void Sound() = 0; // Hàm ảo thuần túy
private:
double m_legs_count; // Số chân của động vật
};
2
3
4
5
6
7
8
Ở đây Sound() là một hàm ảo thuần túy, vì nó được khai báo với chỉ định của hàm ảo thuần túy PURE (=0
).
Hàm ảo thuần túy chỉ là các hàm ảo được đặt chỉ định PURE: (=NULL) hoặc (=0). Ví dụ về khai báo và sử dụng lớp trừu tượng:
class CAnimal
{
public:
virtual void Sound()=`NULL`; // Phương thức PURE, phải được ghi đè trong lớp dẫn xuất, CAnimal giờ là trừu tượng và không thể tạo được
};
//--- Dẫn xuất từ lớp trừu tượng
class CCat : public CAnimal
{
public:
virtual void Sound() { `Print`(`"Myau"`); } // PURE được ghi đè, CCat không phải là trừu tượng và có thể được tạo
};
//--- Ví dụ về sử dụng sai
new CAnimal; // Lỗi của 'CAnimal' - trình biên dịch trả về lỗi "cannot instantiate abstract class"
CAnimal some_animal; // Lỗi của 'CAnimal' - trình biên dịch trả về lỗi "cannot instantiate abstract class"
//--- Ví dụ về sử dụng đúng
new CCat; // Không lỗi - lớp CCat không phải là trừu tượng
CCat cat; // Không lỗi - lớp CCat không phải là trừu tượng
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Hạn chế đối với lớp trừu tượng
Nếu hàm tạo của một lớp trừu tượng gọi một hàm ảo thuần túy (trực tiếp hoặc gián tiếp), kết quả sẽ không xác định.
//+------------------------------------------------------------------+
//| Lớp cơ sở trừu tượng |
//+------------------------------------------------------------------+
class CAnimal
{
public:
//--- Hàm ảo thuần túy
virtual void Sound(void)=`NULL`;
//--- Hàm
void CallSound(void) { Sound(); }
//--- Hàm tạo
CAnimal()
{
//--- Gọi rõ ràng phương thức ảo
Sound();
//--- Gọi ngầm (sử dụng hàm thứ ba)
CallSound();
//--- Hàm tạo và/hoặc hàm hủy luôn gọi các hàm của chính nó,
//--- ngay cả khi chúng là ảo và bị ghi đè bởi một hàm được gọi trong lớp dẫn xuất
//--- Nếu hàm được gọi là ảo thuần túy,
//--- việc gọi nó sẽ gây ra lỗi nghiêm trọng thời gian chạy: "pure virtual function call"
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Tuy nhiên, các hàm tạo và hàm hủy cho các lớp trừu tượng có thể gọi các hàm thành viên khác.