Ví dụ tiếp theo cho thấy rằng sự ràng buộc giữa hàm ảo gốc (ở lớp cơ sở – lớp cha, lớp ông…) và sự thay thế của nó (được định nghĩa trong lớp dẫn xuất – lớp con, lớp cháu…) được tạo một cách linh động (dynamically), trong quá trình thực thi của chương trình.
Hãy xem ví dụ →
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <iostream> using namespace std; class Pet { protected: string Name; public: Pet(string n) { Name = n; MakeSound(); } virtual void MakeSound(void) { cout << Name << " the Pet says: Shh! Shh!" << endl; } }; class Cat : public Pet { public: Cat(string n) : Pet(n) { } void MakeSound(void) { cout << Name << " the Cat says: Meow! Meow!" << endl; } }; class Dog : public Pet { public: Dog(string n) : Pet(n) { } void MakeSound(void) { cout << Name << " the Dog says: Woof! Woof!" << endl; } }; int main(void) { Cat *a_cat; Dog *a_dog; a_cat = new Cat("Kitty"); a_dog = new Dog("Doggie"); return 0; } |
Chúng ta gọi hàm MakeSound là bên trong hàm khởi tạo của Pet. Chúng ta đã biết rằng hàm này thay thế bởi các định nghĩa trong các lớp con của Pet là Cat và Dog. Chúng ta vẫn chưa biết khi nào thay thế đó xảy ra.
Chương trình trên sẽ xuất ra các dòng sau:
1 2 |
Kitty the Pet says: Shh! Shh! Doggie the Pet says: Shh! Shh! |
Điều này có nghĩa là sự ràng buộc giữa các hàm ban đầu và các implementations (implementation của một hàm có thể hiểu là code của hàm đó) đa hình của chúng sẽ được thiết lập sau khi đối tượng lớp con được tạo ra chứ không sớm hơn.