Dẫn xuất và thừa kế - Pdf 64


150
CHƯƠNG 6
DẪN XUẤT VÀ THỪA KẾ
Cùng với sự trừu tượng dữ liệu với tính ñóng gói (encapsulation), còn có hai khái
niệm nữa rất quan trọng ñã làm nên thế mạnh của phương pháp lập trình hướng ñối
tượng ñó là tính kế thừa (inheritance) và tính tương ứng bội (polymorphism). Tính kế
thừa cho phép các lớp ñược xây dựng trên các lớp ñã có ñược ñề cập trong chương
này, tính tương ứng bội sẽ ñược trình bày ở chương tiếp theo.
Trong chương này sẽ nói về sự thừa kế của các lớp.
§
1. SỰ DẪN XUẤT VÀ TÍNH THỪA KẾ
1.1. Lớp cơ sở và lớp dẫn xuất
Một lớp ñược xây dựng thừa kế một lớp khác gọi là lớp dẫn xuất (derived class).
Lớp dùng ñể xây dựng lớp dẫn xuất gọi là lớp cơ sở (base class).
Lớp nào cũng có thể là một lớp cơ sở. Hơn thế nữa, một lớp có thể là cơ sở cho
nhiều lớp dẫn xuất khác nhau. ðến lượt mình, lớp dẫn xuất lại có thể dùng làm cơ sở
ñể xây dựng các lớp dẫn xuất khác. Ngoài ra một lớp có thể dẫn xuất từ nhiều lớp cơ
sở.
Dưới ñây là một số sơ ñồ về quan hệ dẫn xuất của các lớp:
Sơ ñồ 1: Lớp B dẫn xuất từ lớp A,
lớp C dẫn xuất từ lớp B
A

B

C


// Khai báo các thuộc tính
public:
// Các phương thức
} ;

1521.3. Các kiểu thừa kế
Trong ví dụ trên, lớp C thừa kế public các lớp A và B. Nếu thay từ khoá public
bằng private, thì sự thừa kế là private.
Chú ý: Nếu bỏ qua không dùng từ khoá thì hiểu là private, ví dụ nếu ñịnh
nghĩa:
class C : public A, B
{
private:
// Khai báo các thuộc tính
public:
// Các phương thức
} ;
thì A là lớp cơ sở public của C , còn B là lớp cơ sở private của C.
+ Khi thừa kế theo kiểu public: Các thành phần public và protected của lớp cơ sở
sẽ trở thành các thành phần public và protected của lớp dẫn xuất.
+ Khi thừa kế theo kiểu private: Các thành phần public và protected của lớp cơ sở
sẽ trở thành các thành phần private của lớp dẫn xuất.
+ Khi thừa kế theo kiểu protected: Các thành phần public và protected của lớp cơ
sở sẽ trở thành các thành phần protected của lớp dẫn xuất.
1.4. Thừa kế các thành phần dữ liệu
Các thuộc tính của lớp cơ sở ñược thừa kế trong lớp dẫn xuất. Như vậy tập thuộc
tính của lớp dẫn xuất sẽ gồm: các thuộc tính mới khai báo trong ñịnh nghĩa lớp dẫn

B::a , B::b, B::x (kiểu double) - thừa kế từ B
a, x (kiểu char*) và b (kiểu int) - khai báo trong C
Trong các phương thức của C chỉ cho phép truy nhập trực tiếp tới các thuộc tính
khai báo trong C.
1.5. Thừa kế phương thức
Trừ:
+ Hàm tạo
+ Hàm huỷ
+ Toán tử gán
các phương thức (public) khác của lớp cơ sở ñược thừa kế trong lớp dẫn xuất.
Ví dụ: Trong chương trình dưới ñây:
+ ðầu tiên ñịnh nghĩa lớp DIEM có:
Các thuộc tính x, y
Hai hàm tạo
Phương thức in()
+ Sau ñó xây dựng lớp HINH_TRON dẫn xuất từ lớp DIEM, ñưa thêm:
Thuộc tính r
Hai hàm tạo
Phương thức getR
+ Trong hàm main:
Khai báo ñối tượng h kiểu HINH_TRON
Sử dụng phương thức in() ñối với h (sự thừa kế)
Sử dụng phương thức getR ñối với h

154

#include <conio.h>
#include <iostream.h>
class DIEM
{

return r;
}
};
void main()

155

{
HINH_TRON h(2.5,3.5,8);
clrscr();
cout << "\nHinh tron co tam: ";
h.in();
cout << "\nCo ban kinh= " << h.getR();
getch();
}
1.6. Lớp cơ sở và ñối tượng thành phần
Lớp cơ sở thường ñược xử lý giống như một thành phần kiểu ñối tượng của
lớp dẫn xuất. Ví dụ chương trình trong 1.5 có thể thay bằng một chương trình
khác trong ñó thay việc dùng lớp cơ sở DIEM bằng một thành phần kiểu DIEM
trong lớp HINH_TRON. Chương trình mới có thể viết như sau:
#include <conio.h>
#include <iostream.h>
class DIEM
{
double x, y;
public:
DIEM()
{
x = y =0.0;
}

{
return r;
}
};
void main()
{
HINH_TRON h(2.5,3.5,8);
cout << "\nHinh tron co tam: ";
h.in();
cout << "\nCo ban kinh= " << h.getR();
getch();
}
§
2. HÀM TẠO, HÀM HUỶ ðỐI VỚI TÍNH THỪA KẾ
2.1. Những thành phần không thừa kế trong lớp dẫn xuất
Lớp dẫn xuất không thừa kế của lớp cơ sở:
+ Hàm tạo
+ Hàm huỷ
+ Toán tử gán
2.2. Cách xây dựng hàm tạo của lớp dẫn xuất
Hàm tạo cần có các ñối ñể khởi gán cho các thuộc tính (thành phần dữ liệu) của
lớp. Có thể phân thuộc tính làm 3 loại ứng với 3 cách khởi gán khác nhau:

157

+ Các thuộc tính mới khai báo trong lớp dẫn xuất. Trong các phương thức
của lớp dẫn xuất có thể truy xuất ñến các thuộc tính này. Vì vậy chúng
thường ñược khởi gán bằng các câu lệnh gán viết trong thân hàm tạo.
+ Các thành phần kiểu ñối tượng. Trong lớp dẫn xuất không cho phép truy nhập
ñến các thuộc tính của các ñối tượng này. Vì vậy ñể khởi gán cho các ñối tượng thành


158

- Hai hàm tạo, phương thức in() và hàm huỷ
+ Lớp GIAO_VIEN :
- Kế thừa từ lớp NGUOI
- ðưa thêm các thuộc tính
char *bomon ; // Bộ môn công tác
MON_HOC mh ; // Môn học ñang dậy
- Hai hàm tạo , phương thức in() và hàm huỷ
Hãy ñể ý cách xây dựng các hàm tạo, hàm huỷ của lớp dẫn xuất GIAO_VIEN.
Trong lớp GIAO_VIEN có thể gọi tới 2 phương thức in():
GIAO_VIEN::in() // ðược xây dựng trong lớp GIAO_VIEN
NGUOI::in() // Thừa kế từ lớp NGUOI
Hãy chú ý cách gọi tới 2 phương thức in() trong chương trình dưới ñây.
#include <iostream.h>
#include <string.h>
class MON_HOC
{
char *monhoc;
int st;
public:
MON_HOC()
{
monhoc=NULL;
st=0;
}
MON_HOC(char *monhoc1, int st1)
{
int n = strlen(monhoc1);

{
int n = strlen(ht1);
ht = new char[n+1];
strcpy(ht,ht1);
ns=ns1;
}
~NGUOI()
{
if (ht!=NULL)
{
delete ht; ns=0;
}
}
void in()
{
cout << "\nHo ten : " << ht << " nam sinh: " << ns;
}
} ;
class GIAO_VIEN : public NGUOI
{

160

char *bomon;
MON_HOC mh;
public:
GIAO_VIEN():mh(),NGUOI() //Su dung ham tao khong doi
{
bomon=NULL;
}


Giả sử lớp A có:
thuộc tính public a1
thuộc tính protected a2
và lớp B dẫn xuất public từ A, thì A::a1 trở thành public trong B, A::a2 trở thành
protected trong B.
Do ñó nếu dùng B làm lớp cơ sở ñể xây dựng lớp C. Thì trong C có thể truy nhập
tới A::a1 và A::a2.
Thế nhưng nếu sửa ñổi ñể B dẫn xuất private từ A, thì cả A::a1 và A::a2 trở thành
private trong B, và khi ñó trong C không ñược phép truy nhập tới các thuộc tính
A::a1 và A::a2.
ðể biết tường tận hơn, chúng ta hãy biên dịch chương trình:
#include <conio.h>
#include <iostream.h>
#include <string.h>
class A
{
protected:
int a1;
public:
int a2;
A()
{
a1=a2=0;
}
A(int t1, int t2)
{
a1=t1; a2= t2;
}
void in()

{
b1=b2=0;
}
C(int t1, int t2, int u1,int u2)
{
a1=t1; a2=t2; b1=u1;b2=u2;
}
void in()
{
cout << a1;
cout <<" " << a2 << " " << b1 << " " << b2;
}
};
void main()
{
C c(1,2,3,4);
c.in();
getch();

163

}
Chúng ta sẽ nhận ñược 4 thông báo lỗi sau trong lớp C (tại hàm tạo có ñối và
phương thức in):
A::a1 is not accessible
A::a2 is not accessible
A::a1 is not accessible
A::a2 is not accessible
Bây giờ nếu sửa ñổi ñể lớp B dẫn xuất public từ A thì chương trình sẽ không có lỗi
và làm việc tốt.

thức) của lớp cơ sở, kể cả các thành phần mà lớp cơ sở ñược thừa kế.
+ Hãy áp dụng nguyên lý trên ñể xét lớp G:
- Lớp G thừa kế các thành phần của các lớp D và E
- Lớp D thừa kế các thành phần của lớp A và B
- Lớp E thừa kế các thành phần của lớp C
Như vậy các thành phần có thể sử trong lớp G gồm:
- Các thành phần khai báo trong G (của riêng G)

165

- Các thành phần khai báo trong các lớp D, E, A, B, C (ñược thừa kế).
3.3. Sự trùng tên
Như ñã nói trong 3.2: Trong lớp G có thể sử dụng (trực tiếp hay gián tiếp) các
thành phần của riêng G và các thành phần mà nó ñược thừa kế từ các lớp D, E, A, B,
C.
Yêu cầu về cách ñặt tên ở ñây là:
+ Tên các lớp không ñược trùng lặp
+ Tên các thành phần trong một lớp cũng không ñược trùng lặp
+ Tên các thành phần trong các lớp khác nhau có quyền ñược trùng lặp.
ðể phân biệt các thành phần trùng tên trong lớp dẫn xuất, cần sử dụng thêm tên
lớp (xem ví dụ trong 3.4).
3.4. Sử dụng các thành phần trong lớp dẫn xuất
Như ñã nói ở trên, thành phần của lớp dẫn xuất gồm:
+ Các thành phần khai báo trong lớp dẫn xuất
+ Các thành phần mà lớp dẫn xuất thừa kế từ các lớp cơ sở
Quy tắc sử dụng các thành phần trong lớp dẫn xuất:
Cách 1: Dùng tên lớp và tên thành phần. Khi ñó Chương trình dịch C
++
dễ dàng
phân biệt thành phần thuộc lớp nào. Ví dụ:


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status