Phép đa năng hoá
Đa năng hoá là phương pháp cung cấp nhiều hơn một định nghĩa cho tên hàm đã cho trong cùng một phạm vi. Trình biên dịch sẽ lựa chọn phiên bản thích hợp của hàm hay toán tử dựa trên các tham số mà nó được gọi.
Đa năng hoá các hàm (function overloading)
Trong C, các hàm phải có tên khác nhau. Trong C++ ta có thể viết các hàm cùng tên nhưng khác số lượng biến hoặc số biến bằng nhau nhưng kiểu biến khác nhau. Đây là việc đa năng hoá hàm, thuận tiện cho việc viết các hàm thực hiện cùng một công việc.
VD. Trong C:
int abs(int x);
long labs(long x);
double fabs (double d);
Trong C++:
int abs(int x);
long abs(long x);
double abs (double d);
Chú ý: Trong phần này cần đề phòng sự nhập nhằng giữa 2 kiểu int và kiểu float.
Các giới hạn của việc đa năng hoá:
Các hàm đa năng hoá, danh sách biến như nhau nhưng giá rị của hàm khác nhau -> trình biên dịch báo lỗi.
VD khai báo không hợp lệ:
void F(int x);
int F(int x);
- Khai báo typedef không định nghĩa kiểu mới, chỉ thay đổi tên gọi, không ảnh hưởng tới việc đa năng hoá hàm.
107 trang |
Chia sẻ: trungkhoi17 | Lượt xem: 619 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Bài giảng Lập trình hướng đối tượng với C++, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
1Lập trình hướng đối tượng với C++2Nhắc lại một số kiến thức CFile có phần mở rộng C : baitap1.CPhân biệt chữ hoa chữ thườngCấu trúc một chương trình Khai báo các thư viện chuẩn và thư viện người dùngĐịnh nghĩa các kiểu DL mớiKhai báo các biến toàn cụcKhai báo hoặc định nghĩa các hàmChương trình chính (hàm main)Định nghĩa các hàm đã khai báo trước (nếu có)3Nhắc lại một số kiến thức C1. Các biểu thức, toán tửPhép toán số: +, -, *, / (chia nguyên), % (chia dư)Phép toán logic: &&, ||, !Toán tử gán: =, +=, -=, *=, /=VD a += b a = a + bPhép so sánh: ==, >, >=, #include//Ham Nhap du lieu cho mang x co n phan tuint x[20],n;void nhapdl(int x[], int *n){ int i, tg; printf("\n Kich thuoc day:"); scanf("%d", &tg); *n=tg; for (i=0; i#includeint ktnt(int k){for(int j=2; j>biến 1>> biến 2>> ... >>biến n;VD. cout> n; //đọc vào từ bàn phím giá trị cho biến n.Chú ý: Để dùng các dòng nhập xuất trên ta cần khai báo tệp 18IV. Cách chuyển đổi kiểu dữ liệu.Trong C: (kiểu)biểu_thức, còn trong C++ trang bị một cách chuyển đổi kiểu giống như lời gọi hàm: Kiểu (biểu thức).V. Vị trí khai báo biến.Trong C++, khai báo biến tại bất kỳ vị trí nào trong một phạm vi cho trước (không nhất thiết phải ở đầu của phạm vi), xen kẽ việc khai báo dữ liệu với các câu lệnh thực hiện.19VI. Các biến const.Trong C++, các biến const linh hoạt hơn rất nhiều so với C, chúng ta có thể dùng const để quy định kích thước của một mảng như đoạn chương trình sau:const int ArraySize =100;int X[ArraySize];Khi khai báo một biến const trong C++ ta phải khởi tạo một giá trị ban đầu. Trong C++, các biến const được hiểu mặc định là static 20VII. Struct, union và enumTên sau từ khoá struct được xem như tên kiểu cấu trúc: trong C++, một kiểu cấu trúc cũng được định nghĩa như C theo mẫu:struct tên_kiểu_ct {// khai báo các thành phần của cấu trúc };Trong C++ xem tên viết sau từ khoá struct là tên kiểu cấu trúc và có thể dùng nó để khai báo. do đó, để khai báo các biến, mảng cấu trúc trong C++ ta có thể dùng mẫu sau:21Tên_kiểu_ct danh sách biến, mảng, cấu trúc;Trong C ta phải khai báo: struct tên_kiểu_ct biến;VD. Khai báo số phức kiểu cấu trúc:Trong C:struct so_phuc{ float phan_thuc; float phan_ao;};struct so_phuc C;Trong C++:struct so_phuc{ float phan_thuc; float phan_ao;};so_phuc C;22- Khai báo union và enum cũng tương tự như struct.- union không tên, các trường không tên truy xuất trực tiếp bằng tên của chúng.Ví dụ: union {int Num; float Value; };Num = 10;Value = 12.35;23 VIII. Toán tử new và deleteCách dùng toán tử new để cấp phát bộ nhớ như sau:Trong C: Dùng hµm malloc, calloc ®Ó cÊp ph¸t mét vïng nhí. Khai báo một con trỏ để chứa địa chỉ vùng nhớ sẽ được cấp phát: tên_kiểu_DL *p; Ở đây kiểu có thể là:+ Các kiểu dữ liệu chuẩn của C++ như int, long, float, double, char,...+ Các kiểu do người dùng định nghĩa: mảng, hợp, cấu trúc, lớp, ....Sau đó dùng toán tử new như sau: p = new tên_Kiểu_DL; // cấp phát bộ nhớ cho một biến (1 phần tử) 24p = new tên_Kiểu_DL[n]; // cấp phát bộ nhớ cho n phần tửVí dụ: Để cấp phát bộ nhớ cho một biến thực ta dùng câu lệnh sau: float *px; px=new float; Để cấp phát bộ nhớ cho 100 phần tử nguyên ta dùng câu lệnh:int *pn;pn=new int[100]; for (int i=0; i#include #include #include #include #includevoid main() { float *a; float *p; int i, j, m,n; cout >n>>m;30 a= new float[n*m]; clrscr(); randomize();//(stdlib.h) for (p=a; p cout trình biên dịch báo lỗi. VD khai báo không hợp lệ:void F(int x);int F(int x);- Khai báo typedef không định nghĩa kiểu mới, chỉ thay đổi tên gọi, không ảnh hưởng tới việc đa năng hoá hàm.40VD: typedef char *p;void F(char *s);void F(p xau); 2 hàm có cùng danh sách tham số -> lỗiKiểu mảng và kiểu con trỏ là như nhau:VD void F(char * s); void F(char s[]); -> Lỗi.Đối với mảng nhiều chiều thì có sự phân biệtVD: void F(char s[] ); void F(char s[] [7]);- const (tham chiếu) có thể phân biệt41VD: void F(char *s); void F(const char *s);2. Đa năng hoá toán tử (Operator overloading)Trong C, khi thao tác với các kiểu dữ liệu cấu trúc (struct) hoặc lớp (class) thường phải thông qua các hàm.VD: Cộng hai số phức:struct sp{ float thuc; float ao; };struct sp cong(struct sp a, struct sp b){ struct sp c; c.thuc=a.thuc +b.thuc;42 c.ao = a.ao + b.ao; return c;}Khi gọi:struct sp x, y, z;z = cong (x, y);Nhận xét: Việc dùng các hàm để thực hiện các phép tính không được tự nhiên và tỏ ra dài dòng.VD cần thực hiện phép tính: s= (p-q*z)/(u+v) ->gọi hàm phức tạp.Trong C++, cho phép các phép toán để định nghĩa các hàm, ta thường gọi là đa năng hoá toán tử, nạp chồng toán tử hay sự tải bội các toán tử. Và có thể viết biểu thức như trên.43Để đa năng hoá các toán tử, các đối tượng buộc phải là cấu trúc hoặc lớp.Tên hàm toán tử: từ khoá operator và phép toán.Cú pháp: Kiểu_trả_về operator phép_toán (danh sách toán hạng){//tính toán trong hàm return Kết_quả; }VD. Nạp chồng phép toán + 2 số phức:sp operator+ (sp a, sp b){ sp c; c.thuc =a.thuc + b.thuc; c.ao = a.ao + b.ao;return c; }44VD 1. TÝnh biÓu thøc: s = (p-q*z)/(u+v), víi c¸c h¹ng tö lµ c¸c sè phøc. //sophuc.cppCác giới hạn của đa năng hoá toán tử.Không thể định nghĩa các toán tử mới.Hầu hết các toán tử C++ đều có thể đa năng hoá. Các toán tử không được đa năng hóa: ::, .*, ., ?:Không thể thay đổi thứ tự ưu tiên của các toán tử.Không thể thay đổi các ý nghĩa của các toán tử khi áp dụng cho các kiểu có sẵn.Các toán tử được phân loại như sau: Các toán tử một ngôi: !, ++, --, ~.Các toán tử 2 ngôi: *, /, %, +, -, >>, , =, >=, 2.58 5.7346CHƯƠNG III. LỚP VÀ ĐỐI TƯỢNG1. Líp* Khai b¸o:class tªn_líp {public| private | protected:C¸c thµnh phÇn dữ liệupublic| private | protected: - C¸c hµm (ph¬ng thøc - method) }; //kết thúc khai báo lớppublic | private | protected: quy định tầm vực truy xuất các thành phần, private (mặc định)471. Líppublic (thành phần chung): các đối tượng thuộc lớp, các hàm trong lớp dẫn xuất có thể truy xuất (gọi) đến các thành phần này.private (thành phần riêng): các đối tượng thuộc lớp, các hàm trong lớp dẫn xuất không thể truy xuất (gọi) đến các thành phần này, thường để che dấu đối với bên ngoài lớp.protected: các đối tượng thuộc lớp không thể truy xuất (gọi) đến chúng, các hàm trong lớp dẫn xuất có thể truy xuất (gọi) đến các thành phần này481. LípVD.class coso { private: int n; // thµnh phÇn riªng cña líp public: //thành phần chung của lớp float x; nhap() {cout>n; } //hµm } ; //kết thúc lớp49* Đèi tîng thuéc líp kh«ng ®îc gäi c¸c thµnh phÇn riªng cña líp, cã thÓ gäi c¸c thµnh phÇn chung public.* C¸c hµm thuéc líp ®îc gäi c¸c thµnh phÇn riªng cña líp.VD.Víi líp coso ë trªn.void main(){ coso a; // khai b¸o a lµ mét líp coso. cin>>a.n; /*not accessible - kh«ng ®îc v× a lµ ®èi tîng kh«ng ®îc gäi biÕn riªng n */ // a chØ ®îc gäi c¸c thµnh phÇn chung trong líp. cin>>a.x; a.nhap(); //gäi hµm nhap() }50VD x©y dùng líp ma trËn. Trong líp cã hµm nhËp ma trËn dïng cËp ph¸t bé nhí ®éng. Trong hµm main() in ma trËn.class matran {int n, m ; //che dÊu sè hµng sè cét float *a; //che dÊu ma trËn public: nhap() { cout>n>>m; a = new float[n*m]; cout>a[k];}saochep(float *&x, int &u, int &v); //khai b¸o tríc };51V× ma trËn a, n, m bÞ che dÊu nªn ta dïng hµm saochep ®Ó sao chÐp a vµo x, n vµo u, m vµo v.ViÕt hµm saochep ngoµi líp ta viÕt:matran::saochep(float *&x, int &u, int &v){ u = n; v = m;for (int k = 0 ; k kh«ng sî nhÇm)52matran mt;mt.nhap();mt.saochep(x, n, m);)for(i = 0; i p va a cung dia chi.}Víi VD trªn ta dïng con trá xin cÊp ph¸t bé nhí ®éng: DSHS2.cpp543. Con trỏ this.Trong nội bộ lớp có một con trỏ ngầm định gọi là con trỏ this. Khi một đối tượng của lớp được tạo ra thì con trỏ this sẽ mang địa chỉ của đối tượng đó - trỏ tới chính nó. VD 1.class DIEM {int x, y; void nhapsl(); } ;void DIEM::nhapsl(){ cout>x>>y;}void DIEM::nhapsl(){cout> this ->x >>this->y;}55Xét lời gọi hàm tới phương thức nhapsl(): DIEM d1; d1.nhapsl();Tham số truyền cho con trỏ this chính là địa chỉ của d1: this = &d1Do đó: this -> x chính là d1.x this ->y chính là d1.yNhư vậy : d1.nhapsl() chính là nhập dữ liệu cho các thuộc tính của đối tượng d1.Kết luận: Tham số truyền cho đối con trỏ this chính là địa chỉ của đối tượng đi kèm với phương thức trong lời gọi hàm.VD 3.17.564. Hàm tạo (constructor), hàm huỷ (destructor).Thông thường có một hàm tạo và hàm huỷ ngầm định.4.1. Hàm tạo: là một phương thức của lớp, tự động thực hiện khi một đối tượng được khai báo. Hàm tạo sẽ khởi gán giá trị cho các thuộc tính của đối tượng và chuẩn bị một số việc cho đối tượng mới.Cách viết:a. Điểm khác của hàm tạo và phương thức thông thường.Tên hàm tạo trùng với tên lớp.Không khai báo kiểu cho hàm tạo.Không có kết quả trả về.b. Điểm giống nhau của hàm tạo và phương thức thông thường.57Hàm tạo có thể được xây dựng bên trong hoặc bên ngoài lớp.Có đối hoặc không có đối. Hàm tạo không đối thay cho hàm tạo ngầm định. Hàm tạo ngầm định không thực hiện sự khởi tạo nào.Trong lớp có thể có nhiều hàm tạo (cùng tên, khác đối)VD.dùng hàm tạo khởi gán giá trị.class DIEM { int x, y;DIEM() { x = y = 0; }//hàm tạo trong lớpDIEM(int x1, int y1);};DIEM::DIEM(int x1, int y1){ x = x1; y = y1; } //hàm tạo ngoài lớp.58Dùng để cấp phát bộ nhớ động.VD class dayso{int n;float *a;public: dayso() { this->n = 0; this -> a = NULL; }dayso(int n1) //cấp phát bộ nhớ động cho mảng n1 phần tử.{this ->n = n1;this ->a = new float[n1 +1];}59b. Dùng hàm tạo trong khai báo.Dùng hàm tạo trong khai báo để khởi gán giá trị cho các thuộc tính của đối tượng.Lệnh khai báo một biến sẽ gọi hàm tạo một lần.VD: DIEM d; //gọi hàm tạo không đối //d.x = 0, d.y = 0DIEM u(200, 100); //gọi hàm tạo có đối //kết quả: u.x = 200, u.y = 100DIEM p[10];// gọi hàm tạo không đối 10 lần.DIEM *p;p = new DIEM(100, 200);// gọi tới hàm tạo có đối // p-> x = 100, p->y = 200604.2 Hàm huỷ.Hàm huỷ của một đối tượng được khai báo trong một hàm sẽ tự động hoạt động khi hàm kết thúc công việc, thực hiện một số công việc có tính “dọn dẹp” trước khi đối tượng được huỷ ví dụ giải phóng vùng nhớ.Việc huỷ một đối tượng thường xảy ra trong 2 trượng hợp: + Trong các toán tử và các hàm giải phóng vùng nhớ, như delete, free,.. + Giải phóng các biến, mảng cục bộ khi thoát khỏi hàm, phương thức,...Hàm huỷ là thành viên đặc biệt của lớp, khai báo: ~tên_lớp() {... }61- Hàm huỷ không có kiểu, không có giá trị trả về, không có đối và không cho phép đa năng hoá.VD1: class lop { public: ~lop() {puts(“Ham huy”); } };VD2: Hàm huỷ cho lop dayso:class dayso{ int n; float *a; public: ~dayso() { this-> n = 0; delete this -> a; }};VD3 bài C3_8 (CD)625 . Hàm tạo sao chép.Tạo ra một đối tượng mới như một đối tượng đã có nhưng độc lập với đối tượng đó.Khi lớp không có thuộc tính kiểu con trỏ hoặc tham chiếu thì ta dùng hàm tạo sao chép mặc định là đủ:VD tạo đối tượng sp u giống d khai báo: SP u(d);- Khi lớp có các thuộc tính con trỏ hoặc tham chiếu không đáp ứng yêu cầu trên vì khi đó thuộc tính của đối tượng này thay đổi thì đối tượng kia cũng thay đổi theo hoặc khi một trong 2 đối tượng bị giải phóng thì đối tượng còn lại cũng không còn vùng nhớ nữa. Do các thuộc tính của chúng dùng chung vùng nhớ ->Ta cần tạo hàm tạo sao chép:63Cách viết:Tên_lớp (const Tên_lớp & đối_tượng){ // Các lệnh dùng các thuộc tính của đối tượng //khởi gán cho các thuộc tính của đối tượng mới}VD1. Tsaochep.cpp646. Đối tượng hằng, phương thức hằng.6. 1. Đối tượng hằng.Giống như các phần tử dữ liệu khác, một đối tượng có thể được khai báo là hằng.VD class DIEM { int x, y; DIEM () { x = y = 0; } DIEM(int x1, int y1) { x = x1; y = y1; } };const DIEM d = DIEM(100, 200);//Khai báo đối tượng hằng.- Khi khai báo cần sử dụng hàm tạo để khởi gán giá trị cho đối tượng hằng.65Về lý thuyết ta không thể thay đổi được đối tượng hằng nhưng các hàm có thể thay đổi các thuộc tính của nó và có cảnh báo: Non- const called for const object.Ta không thể thay đổi tượng const bằng phép gán vì nó phải được khởi động.6.2. Phương thức hằng.Trong thân phương thức không cho phép thay đổi thuộc tính của đối tượng.Cách viết: thêm từ khoá const vào sau dòng đầu của phương thức.VD1 const.CPP.VD2: C3_14.CPP667. Toán tử gánĐối với một lớp luôn có toán tử gán mặc định.Khi lớp có các thành phần dự liệu là con trỏ hoặc tham chiếu, ta cần xây dựng toán tử gán.Cách viết:void operator=(const Tên_lớp &tham_số){//gán các thành phần DL của tham_số cho con trỏ this }Hoặc:const Tên_lớp &operator=(const Tên_lớp &tham_số){//gán các thành phần DL của tham_số cho con trỏ this return tham_số;}67VD: Xây dựng toán tử gán cho lop NGUOI gồm họ tên và tuổi:class nguoi{private: char *hoten; int tuoi; public:nguoi() //hàm tạo không đối{ hoten=new char[30]; tuoi=0; }7. Toán tử gán68void operator=(const nguoi &p){ strcpy(this->hoten, p.hoten); this->tuoi=p.tuoi; } Hoặc:/*const nguoi &operator=(const nguoi &p){ strcpy(this->hoten,p.hoten); this->tuoi=p.tuoi; return p;} */7. Toán tử gán698. Hàm bạn, lớp bạn8.1 Hàm bạn (friend function).a. Tính chất.Hàm bạn của một lớp không phải là phương thức của lớp nhưng trong thân hàm có thể truy cập đến thành phần riêng của lớp. Đây chính là sự khác nhau duy nhất giữa hàm bạn và hàm thông thường.Phương thức có thể dùng con trỏ this, hàm bạn thì không.Lời gọi hàm bạn giống như hàm thông thường.b. Cách viết.Cách 1: Dùng từ khoá friend để khai báo hàm trong lớp và xây dựng hàm bên ngoài lớp như các hàm thông thường (không dùng từ khoá friend). Mẫu như sau:70class A{ private: // khai báo các thuộc tính public: //khai báo các hàm bạn của lớp friend void f1(); friend int f2(); };//xây dựng các hàm f1, f2 void f1() {.. } int f2 () {}71Cách 2: Dùng từ khoá friend để xây dựng hàm trong định nghĩa lớp. Mẫu như sau:class A { private: // khai báo các thuộc tính public: //Xây dựng các hàm bạn của lớp A friend void f1() { . } friend int f2() {.. } };72VD. So sánh phương thức, hàm bạn và hàm thông thường. Xét lớp số phức, thực hiện cộng 2 số phức:PA1: dùng phương thức.class SP{ double a, b;//phan thuc, ao public: SP cong( SP u2) { SP u; u.a = this->a+ u2.a;//dung con tro this u.b = this->b + u2.b; return u; }};void main() { SP u, u1, u2; u = u1.cong(u2);}73PA2: Dùng hàm bạn.class SP{ double a;//phan thuc double b;//phan ao public: friend SP cong( SP u1, SP u2) { SP u; u.a = u1.a+ u2.a; u.b = u1.b + u2.b; return u; }};void main(){ SP u, u1, u2; u = cong(u1,u2);}74PA3: Dùng hàm thông thường.class SP{ double a;//phan thuc double b;//phan ao public: };SP cong( SP u1, SP u2) { SP u; u.a = u1.a+ u2.a; u.b = u1.b + u2.b; return u; }75c. Một hàm có thể làm bạn của nhiều lớp.Một hàm là bạn của nhiều lớp, thì nó có thể truy nhập đến tất cả các thuộc tính của các lớp này. Để hàm F trở thành bạn của các lớp A và B:class A; //Khai báo trướcclass B; //Định nghĩa lớp Aclass A { //khai báo F là hàm bạn của A friend void F(...); };// Định nghĩa lớp class B { // Khai báo F là hàm bạn của B friend void F(...); };76//Xây dựng hàm F:void F(...){ .... }VD. Xây hµm b¹n ®Ó tÝnh tÝch cña ma trËn vµ vÐc t¬.friend.CPP.6.2 Líp b¹n.a. Tính chấtNếu lớp A được khai báo là bạn của lớp B thì tất cả các phương thức của A đều có thể truy nhập đến các thành phần riêng của lớp B. Một lớp có thể là bạn của nhiều lớp, Cũng có thể khai báo A là bạnc ủa B và B là bạn của A.77b. Cách khai báo.Giả sử có 3 lớp A, B, C, khai báo theo mẫu:class A;class B;class C; // khai báo trước//Định nghĩa các lớpclass A{ ..... friend class B; //Lớp B là bạncủa A friend class C; // Lớp C là bạn của A.... };78class B{ ... friend class A;// Lớp A là bạn của B friend class C; // Lớp C là bạn cảu B..... };class C{..... friend class B;// Lớp B là bạn của C... };VD. Lớp MT là bạn của lớp VT. Nhập, in ma trận, véc tơ, Tính tích của chúng. (classfri.cpp)799. Nạp chồng toán tử.9.1. Nạp chồng toán tử ngoài lớp.Không thể dùng con trỏ this, kh«ng lµ hµm thµnh viªn cña líp, thêng lµ hµm b¹nVDclass sp{private: double a, b;public: void nhap(){cout>a>>b; }void in() { couta+p.a; x.b=this ->b+p.b; return x; }};82HoÆcclass sp{.....sp operator+(sp p){this->a = this ->a+p.a this ->b = this->b+p.b} };void main(){ sp q, p; p.nhap(); q.nhap(); p+q; p.in(); getch(); }839.3. Nạp chồng toán tử chèn dòng >.Đa năng hoá toán tử >:istream & operetor >> (istream & in, Tên_lớp đt)Hàm toán tử trả về tham chiếu chỉ đến dòng nhập istream, tham số thứ nhất là một tham chiếu chỉ đến dòng nhập istream tham số thứ 2 là đối tượng.- Để dùng toán tử > luôn nhất quán chúng ta không thể định nghĩa hàm toán tử > là hàm thành viên, thông thường là hàm friend84VD. Viết nạp chồng toán tử >>, các hàm huiuỷ tương Khi xây dùng hµm huû cho líp dÉn xuÊt ta chØ cÇn quan t©m ®Õn c¸c thuéc tÝnh (kh«ng ph¶i lµ ®èi tîng) khai b¸o trong líp dÉn xuÊt.967. To¸n tö g¸n cho líp dÉn xuÊtKhi thuéc tÝnh cã thuéc tÝnh (kÓ c¶ c¸c thuéc tÝnh kÕ thõa tõ líp c¬ së) lµ con trá th× nhÊt thiÕt cÇn x©y dùng to¸n tö g¸n.C¸ch x©y dùng to¸n tö g¸n:B1: x©y dùng to¸n tö g¸n cho líp c¬ së.X©y dùng ph¬ng thøc (trong c¸c líp c¬ së) ®Ó nhËn ®Þa chØ cña ®èi tîng Èn cña líp:Tªn_Líp* get_DT() { return this; }B2: x©y dùng to¸n tö g¸n cho líp dÉn xuÊt: ta dïng ph¬ng thøc trªn ®Ó nhËn ®Þa chØ cña ®èi tîng líp c¬ së mµ líp dÉn xuÊt kÕ thõa, sau ®ã thùc hiÖn lÖnh g¸n trªn 2 ®èi tîng nµy: 977. To¸n tö g¸n cho líp dÉn xuÊtclass A { . A operator =(A & h){//c¸c c©u lÖnh thùc hiÖn lÖnh g¸n cho A }//ph¬ng thøc nhËn ®Þa chØ ®èi tîng Èn cña líp:A* get_A(){ return this; }};//líp kÕ thõa Bclass B:public A{..B& operator=(B&h){ A *u1, *u2; u1= this->get_A()987. To¸n tö g¸n cho líp dÉn xuÊtu2 = h.get_A();*u1= *u2; //sö dông phÐp g¸n trong A ®Ó g¸n c¸c thuéc tÝnh B kÕ thõa tõ A//c¸c lÖnh thùc hiÖn g¸n c¸c thuéc tÝnh riªng cña B}};998. Hàm tạo sao chép của lớp dẫn xuất.Tương tự như toán tử gán, khi các thuộc tính (kể cả các thuộc tính kế thừa) là con trỏ cần xây dựng hàm tạo sao chép để tạo ra đối tượng mới giống và độc lập với đối tượng đã cho.Cách xây dựng:B1: Xây dựng toán tử gán cho lớp dẫn xuấtB2: Xây dựng hàm tạo sao chép cho lớp dẫn xuất theo mẫu:Tên_lớp_dẫn_xuất(Tên_lớp_dẫn_xuất & h){ *this = h; }1009. Các lớp cơ sở ảoTa không thể khai báo 2 lần cùng một lớp trong danh sách các lớp cơ sở của một lớp dẫn xuấtChẳng hạn: class B: public A, public A {....... };Hoặc một lớp cơ sở được đề cập nhiều hơn một lần trong các lớp cơ sở trung gian của các lớp dẫn xuất.VD.#include class A { public: int a; };class B : public A{ public: int b; };101class C: public A{public : int c };class D:public B, public C{public : tin d; };void main(){ D d;h.d = 4;h.c = 3;h.b = 2;h.a = 1;//Lỗi }Có 2 lớp cơ sở A cho lớp D -> lỗiLỗi trên là do chương trình không nhận biết được thuộc tính a được kế thừa thông qua B hay C.102Giải pháp: khai báo A như một lớp cơ sở kiểu ảo cho cả B và C bằng cách dùng từ khoá virtual:class B : virtual public A{ public: int b; };class C: virtual public A{public : int c };Các lớp cơ sở ảo kết hợp để tạo một lớp cơ sở duy nhất cho các dẫn xuất từ chúng. Như vậy D chỉ có một lớp cơ sở A duy nhấtDo đó h.a = 1; gán 1 cho thuộc tính a của lớp cơ sở A duy nhất mà D kế thừa.103CHƯƠNG V. TÍNH ĐA HÌNH1. Tính đa hình.Tính đa hình là khả năng thiết kế và cài hệ thống mà có thể mở rộng dễ dàng hơn. Các chương trình có thể được viết để xử lý tổng quát như các đối tượng lớp cơ sở.Khả năng cho phép một chương trình sau khi đã biên dịch có nhiều diễn biến xảy ra là một trong những thể hiện của tính đa hình, một thông điệp gửi đi (gửi đến đối tượng) mà không cần biết đối tượng thuộc lớp nào.1042. Phương thức không ảo, phương thức ảo.a. Lời gọi phương thức không ảo.Giả sử có lớp cơ sở A, lớp B dẫn xuất từ A, lớp C dẫn xuất từ B. Trong các lớp A, B, C đều có phương thức hien_thi().Ví dụ.A *p, *q, *r; //các con trỏ kiểu A A a; //a là đối tượng lớp A B b; //b là đối tượng lớp B C c; //c là đối tượng lớp C p = &a; q = &b; r = &c; 105Xét các lời gọi phương thữc tĩnh từ các con trỏ p, q, r: p->hien_thi(); (1) q->hien_thi(); (2) r->hien_thi(); (3)Khi đó mặc dù p, q, r mang địa chỉ của lớp A, B, C nhưng p, q, r đều có kiểu A nên 3 lời gọi trên đều gọi đến A::hien_thi()Quy tắc gọi phương thức không ảo: Nếu lời gọi xuất phát từ một đối tượng của lớp nào thì phương thức lớp đó sẽ được gọi.Nếu lời gọi xuất phát từ một con trỏ kiểu lớp nào thì phương thức lớp đó được gọi bất kể con trỏ mang địa chỉ của lớp nào.106b. Phương thức ảo.Với các lớp A, B, C trên. Để định nghĩa các phương thức hien_thi() của các lớp là phương thứ ảo:Thêm từ khoá virtual vào dòng tiêu đề của phương thức bên trong định nghĩa lớp cơ sở AHoặc thêm từ khoá virtual vào dòng tiêu đề của phương thức bên trong định nghĩa các lớp A, B, C.* Quy tắc gọi phương thức ảo: khác với lời gọi phương thức tĩnh, khi gọi từ một con trỏ thì con trỏ tới đối tượng của lớp nào thì phương thức của lớp đó sẽ được gọi.107Với ví dụ phần a, ta định nghĩa phương thức hien_thi() là phương thức ảo thì (1), (2), (3) lần lượt gọi phương thức hien_thi() của lớp A, B, C.
Các file đính kèm theo tài liệu này:
- bai_giang_lap_trinh_huong_doi_tuong_voi_c.ppt