Phươngthứctĩnh 1.1. Lời gọi tới phươngthứctĩnh Như đã biết một lớp dẫn xuất được thừa kế các phươngthức của các lớp cơ sở tiền bối của nó. Ví dụ lớp A là cơ sở của B, lớp B lại là cơ sở của C, thì C có 2 lớp cơ sở tiền bối là B và A. Lớp C được thừa kế các phươngthức của A và B. Các phươngthức mà chúng ta vẫn nói là các phươngthức tĩnh. Để tìm hiểu thêm về cách gọi tới các phươngthức tĩnh, ta xét ví dụ về các lớp A, B và C như sau: class A { public: void xuat() { cout << "\n Lop A " ; } }; class B:public A { public: void xuat() { cout << "\n Lop B " ; } }; class C:public B { public: void xuat() { cout << "\n Lop C " ; } }; Lớp C có 2 lớp cơ sở tiền bối là A , B và C kế thừa các phươngthức của A và B. Do đó một đối tượng của C sẽ có tới 3 phươngthức xuat. Hãy theo rõi các câu lệnh sau: C h ; // h là đối tượng kiểu C h.xuat() ; // Gọi tới phươngthức h.D::xuat() h.B::xuat() ; // Gọi tới phươngthức h.B::xuat() h.A::xuat() ; // Gọi tới phươngthức h.A::xuat() Các lời gọi phươngthức trong ví dụ trên đều xuất phát từ đối tượng h và mọi lời gọi đều xác định rõ phươngthức cần gọi. 317 318 Bây giờ chúng ta hãy xét các lời gọi không phải từ một biến đối tượng mà từ một con trỏ. Xét các câu lệnh: A *p, *q, *r; // p, q, r là con trỏ kiểu A A a; // a là đối tượng kiểu A B b; // b là đối tượng kiểu B C c; // c là đối tượng kiểu c Chúng ta hãy ghi nhớ mệnh đề sau về con trỏ của các lớp dẫn xuất và cơ sở: Phép gán con trỏ: Con trỏ của lớp cơ sở có thể dùng để chứa địa chỉ các đối tượng của lớp dẫn xuất. Như vậy cả 3 phép gán sau đều hợp lệ: p = &a ; q = &b ; r = &c ; Chúng ta tiếp tục xét các lời gọi phươngthức từ các con trỏ p, q, r: p->xuat(); q->xuat(); r->xuat(); và hãy lý giải xem phươngthức nào (trong các phươngthức A::xuat, B::xuat và C::xuat) được gọi. Câu trả lời như sau: Cả 3 câu lệnh trên đều gọi tới phươngthức A::xuat() , vì các con trỏ p, q và r đều có kiểu A. Như vậy có thể tóm lược cách thức gọi các phươngthứctĩnh như sau: Quy tắc gọi phươngthức tĩnh: Lời gọi tới phươngthứctĩnh bao giờ cũng xác định rõ phươngthức nào (trong số các phươngthức trùng tên của các lớp có quan hệ thừa kế) được gọi: 1. Nếu lời gọi xuất phát từ một đối tượng của lớp nào, thì phươngthức của lớp đó sẽ được gọi. 2. Nếu lời gọi xuất phát từ một con trỏ kiểu lớp nào, thì phươngthức của lớp đó sẽ được gọi bất kể con trỏ chứa địa chỉ của đối tượng nào. 1.2. Ví dụ Xét 4 lớp A, B, C và D. Lớp B và C có chung lớp cơ sở A. Lớp D dẫn xuất từ C. Cả 4 lớp đều có phươngthức xuat(). Xét hàm: void hien(A *p) { p->xuat(); } Không cần biết tới địa chỉ của đối tượng nào sẽ truyền cho đối con trỏ p, lời gọi trong hàm luôn luôn gọi tới phươngthức A::xuat() vì con trỏ p kiểu A. Như vậy bốn câu lệnh: hien(&a); hien(&b); hien(&c); 319 320 hien(&d); trong hàm main (của chương trình dưới đây) đều gọi tới A::xuat(). //CT6-01 // Phuongthuctinh #include <conio.h> #include <stdio.h> #include <iostream.h> #include <ctype.h> class A { private: int n; public: A() { n=0; } A(int n1) { n=n1; } void xuat() { cout << "\nLop A: "<< n; } int getN() { return n; } }; class B:public A { public: B():A() { } B(int n1):A(n1) { } void xuat() { cout << "\nLop B: "<<getN(); } }; class C:public A { public: C():A() { } C(int n1):A(n1) { } void xuat() { cout << "\nLop C: "<<getN(); } }; class D:public C { public: D():C() { } D(int n1):C(n1) { } void xuat() { cout << "\nLop D: "<<getN(); } }; void hien(A *p) { p->xuat(); } void main() { A a(1); B b(2); 321 322 C c(3); D d(4); clrscr(); hien(&a); hien(&b); hien(&c); hien(&d); getch(); } . lược cách thức gọi các phương thức tĩnh như sau: Quy tắc gọi phương thức tĩnh: Lời gọi tới phương thức tĩnh bao giờ cũng xác định rõ phương thức nào (trong. lớp cơ sở tiền bối là B và A. Lớp C được thừa kế các phương thức của A và B. Các phương thức mà chúng ta vẫn nói là các phương thức tĩnh. Để tìm hiểu thêm