Download as pdf or txt
Download as pdf or txt
You are on page 1of 63

ĐẠI HỌC KINH TẾ KỸ THUẬT CÔNG NGHIỆP

KHOA CÔNG NGHỆ THÔNG TIN

LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG

CHƯƠNG 4.
KỸ THUẬT KẾ THỪA

Năm học 2021 - 2022 1


MỤC ĐÍCH CỦA CHƯƠNG

Nội dung tập trung trình bày các vấn đề về kỹ thuật


kế thừa trong lập trình hướng đối tượng trên C++
như:

• Khái niệm kế thừa, cách định nghĩa các lớp trong


mối quan hệ kế thừa, phạm vi truy xuất các thành phần
trong kế thừa.

• Hiểu và phân loại được các dạng kế thừa: đơn kế


thừa, đa kế thừa.

2
CÁC NỘI DUNG CHÍNH

4.1. Đơn kế thừa

4.2. Đa kế thừa

4.3. Các lớp cơ sở ảo

3
GIỚI THIỆU
Thừa kế là một kỹ thuật quan trọng trong lập trình hướng đối tượng. Kỹ
thuật này cho phép lập trình viên sử dụng lại mã lệnh chương trình. Từ đó giúp
làm giảm thời gian và công sức cần thiết để phát triển chương trình đồng thời
tăng sức tin cậy của chương trình đó

 Kế thừa cho phép các lớp được xây dựng từ các lớp khác đã có

 Một lớp được xây dựng kế thừa 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).

4
GIỚI THIỆU
Lớp dẫn xuất sẽ kế thừa:

 Các thành phần (dữ liệu, hàm) của lớp cơ sở;

 Đồng thời bổ sung các thành phần mới.

Lớp nào trong chương trình cũng có thể là một lớp cơ sở hay cụ thể hơn
một lớp dẫn xuất có thể là lớp cơ sở cho một lớp khác

5
GIỚI THIỆU
Một số sơ đồ minh họa tính kế thừa

Động vật
point

coloredpoint Động vật có vú Loài bò sát

Ngựa Chó Thằn lằn Rắn

6
GIỚI THIỆU
Một số sơ đồ minh họa tính kế thừa

Công dân

Cán bộ giảng dạy Cán bộ quản lý

Trưỏng bộ môn

7
GIỚI THIỆU
Tính kế thừa và đặc trưng của lớp kế thừa
Lớp cơ sở
Đặc trưng A
Các đặc trưng này
Đặc trưng B được định nghĩa ở
Đặc trưng C lớp cơ sở

Lớp kế thừa Đặc trưng này được


Đặc trưng A định nghĩa ở lớp kế
Đặc trưng B thừa
Đặc trưng C
Đặc trưng D
8
4.1. ĐƠN KẾ THỪA
Khái niệm:
Một lớp dẫn xuất chỉ kế thừa từ một lớp cơ sở gọi là đơn kế thừa
Cú pháp khai báo đơn kế thừa:

class <Tên_lớp_cơ_sở>
{
// Nội dung lớp cơ sở
};
class <Tên_lớp_dẫn_xuất> : Kiểu_thừa_kế <Tên_lớp_cơ_sở>
{
//Nội dung lớp dẫn xuất
};
9
4.1. ĐƠN KẾ THỪA

Trong đó:
Kiểu_thừa_kế có thể là:
 public
 private
 protected
Kiểu thừa kế chỉ rõ các thành phần của lớp cơ sở sẽ được kế
thừa theo cách nào.
Nếu được bỏ trống chương trình ngầm hiểu là private.

10
4.1. ĐƠN KẾ THỪA
Ví dụ

11
4.1. ĐƠN KẾ THỪA
class Box
{
float hight, weight;
public:
Lớp cơ sở
void Set()
{
cout<<"\n Input hight: "; cin>> hight;
cout<<"\n Input weight: "; cin>> weight;
}
void Display()
{
cout<<"hight = "<<hight<<"\tweight= "<<weight<<endl;
}
};
12
4.1. ĐƠN KẾ THỪA
class ColorBox: public Box
{ int color;
Lớp dẫn
public: xuất
void SetColor()
{ Set();
cout<<"\n Input color: "; cin>>color;
}
void DisplayColor()
{
Display();
cout<<"color= "<<color<<endl;
}
}; 13
4.1. ĐƠN KẾ THỪA
main()

{ Box a;

ColorBox b;

cout<<"\n - Input Box a:"<<endl; a.Set();

cout<<"\n - Output Box a:"<<endl; a.Display();

cout<<"\n - Input ColorBox b:"<<endl;

b.SetColor();

cout<<"\n - Output ColorBox b:"<<endl;

b.DisplayColor();

b.Display(); /* Gọi hàm Display kế thừa từ lớp Box để in ra hight và weight*/

14
}
4.1. ĐƠN KẾ THỪA

Mỗi đối tượng lớp dẫn xuất ColorBox gồm:

 Thành phần dữ liệu và hàm mà lớp Box có

 Bổ sung thêm các thành phần riêng.

15
4.1. ĐƠN KẾ THỪA
Chú ý:
 Trong C++ không phải mọi hàm thành phần đều có thể truyền qua tính kế
thừa. Cụ thể một số trường hợp sau đây không cho phép sử dụng tính kế
thừa.
• Hàm tạo.
• Hàm hủy.
• Các toán tử mới do người dùng định nghĩa.
• Các toán tử gán do người dùng định nghĩa
• Quan hệ friend.

16
4.1. ĐƠN KẾ THỪA
Chú ý:
 Lớp dẫn xuất không được phép truy nhập đến thành phần private của lớp cơ sở.
 Được phép khai báo bên trong lớp dẫn xuất các thành phần cùng tên với các
thành phần đã có trong lớp cơ sở.
<Hai thành phần cùng tên này có thể cùng kiểu hay khác kiểu. Lúc này bên trong một đối tượng của
lớp dẫn xuất có tới hai thành phần khác nhau có cùng tên, nhưng trong phạm vi lớp dẫn xuất tên chung
đó nhằm chỉ định thành phần được khai báo lại trong lớp dẫn xuất.>

Khi muốn chỉ định thành phần cùng tên trong lớp cơ sở, phải sử dụng
tên lớp cơ sở và toán tử phạm vi :: đặt trước tên thành phần đó với cú pháp:
<Tên_lớp_cơ_sở> :: <Tên_thành_phần>
 Trong trường hợp chương trình sử dụng nhiều mức độ kế thừa khác nhau, toán
tử phạm vi vẫn cho phép truy nhập đến bất kể thành phần của lớp cơ sở nào.
17
4.1. ĐƠN KẾ THỪA
Ghi đè hàm thành phần của lớp cơ sở
 Một lớp dẫn xuất có thể ghi đè hàm (overriding function) thành phần lớp cơ
sở. Hàm ghi đè và hàm bị ghi đè giống hệt nhau về tên, tham số và giá trị
trả về, chúng chỉ khác nhau ở vị trí, một hàm đặt trong lớp dẫn xuất và hàm
kia thì có mặt trong lớp cơ sở.

 Một đối tượng lớp dẫn xuất gọi đến hàm ghi đè hoặc khi hàm đó được gọi
trong lớp dẫn xuất, hàm ghi đè của lớp dẫn xuất được gọi một cách tự
động. Muốn gọi đến hàm đó ở lớp cơ sở cần sử dụng toán tử định phạm
vi :: đặt trước tên hàm.

 Ví dụ: Tạo lớp điểm trên mặt phẳng point có thành phần dữ liệu x,y. Lớp
điểm màu coloredpoint kế thừa từ lớp point và bổ sung thành phần màu
color:
18
4.1. ĐƠN KẾ THỪA
class point
{ float x,y;
public:
void Set(int a, int b)
{ x=a; y=b; }
void display()
{ cout<<"Toa do : "<<x<<" "<<y<<endl;}
};
class coloredpoint : public point
{ unsigned int color;
public:
void SetColor(int mau)
{ color= mau;}
void display() /* Ghi đè hàm display() của lớp cơ sở*/
{point::display(); /*gọi tới hàm cùng tên trong lớp cơ sở*/
cout<<"Mau "<<color<<endl;}
19
4.1. ĐƠN KẾ THỪA
main()

coloredpoint n ;

n.Set(4,5);

n.SetColor(6);

cout<<"Diem mau n \n";

n.display();/*Gọi tới hàm của lớp dẫn xuất coloredpoint */

cout<<"Chi hien thi toa do cua n\n";

n.point::display(); /* Gọi tới hàm của lớp cơ sở point */

} 20
4.1. ĐƠN KẾ THỪA
 Hàm tạo và hàm hủy trong kế thừa

Hàm tạo: Cú pháp định nghĩa hàm tạo lớp dẫn xuất:

Hàmtạolớpdẫnxuất(Dsthamsố) : Hàmtạolớpcơsở(Dsthamsố)

// Nội dung hàm tạo lớp dẫn xuất

21
4.1. ĐƠN KẾ THỪA
 Hàm tạo và hàm hủy trong kế thừa

Hàm tạo: Quy tắc định nghĩa hàm tạo lớp dẫn xuất như sau:

- Nếu lớp cơ sở và lớp dẫn xuất không định nghĩa hàm tạo thì hàm tạo
ngầm định của hai lớp sẽ đươc gọi theo đúng thứ tự.

- Nếu lớp cơ sở và lớp dẫn xuất có định nghĩa hàm tạo thì khi định nghĩa
hàm tạo lớp dẫn xuất luôn mô tả một lời gọi tới một trong các hàm tạo
tương ứng ở lớp cơ sở.

+ Hàm tạo không tham số của lớp dẫn xuất có thể có hoặc không cần
mô tả lại một lời gọi đến hàm tạo không tham số lớp cơ sở.

+ Hàm tạo có tham số của lớp dẫn xuất cần thiết phải mô tả lại một
lời gọi đến hàm tạo có tham số lớp cơ sở tương ứng. 22
4.1. ĐƠN KẾ THỪA
 Hàm tạo và hàm hủy trong kế thừa

Hàm hủy: Hàm hủy thứ tự gọi ngược lại với hàm tạo. Khi hủy đối tượng
hàm hủy lớp dẫn xuất được gọi trước, rồi đến hàm hủy lớp cơ sở.

23
4.1. ĐƠN KẾ THỪA
 Hàm tạo và hàm hủy trong kế thừa

Nhận xét:

 Hàm tạo không được kế thừa.

 Nếu muốn sử dụng hàm tạo không tham số của lớp cơ sở thì có thể
không cần mô tả cùng với định nghĩa của hàm tạo lớp dẫn xuất

 Các tham số mà hàm tạo lớp dẫn xuất truyền cho hàm tạo lớp cơ sở
không nhất thiết lấy nguyên si từ các tham số nó nhận được mà có thể
được thay đổi đi ít nhiều.

 Nếu lớp có thành phần dữ liệu con trỏ phải định nghĩa hàm hủy ngược lại
không bắt buộc.
24
4.1. ĐƠN KẾ THỪA
 Hàm tạo và hàm hủy trong kế thừa

Hàm tạo sao chép:

 Nếu trong lớp dẫn xuất không khai báo tường minh hàm tạo sao chép, thì
công việc này được chương trình biên dịch đảm nhiệm nhờ định nghĩa hàm
tạo sao chép ngầm định.

 Về nguyên tắc, trong định nghĩa của hàm tạo sao chép lớp dẫn xuất có
thể mô tả bất kỳ hàm tạo sao chép hoặc hàm tạo nào có mặt trong lớp cơ
sở. Lớp có thành phần dữ liệu con trỏ phải định nghĩa hàm tạo sao chép,
ngược lại không bắt buộc.

 Ví dụ: 4.3 <Tài liệu học tập>

25
4.1. ĐƠN KẾ THỪA
 Con trỏ và kế thừa

• Tương thích giữa đối tượng thuộc lớp dẫn xuất với đối tượng
thuộc lớp cơ sở:

 Một đối tượng của lớp dẫn xuất có thể thay thế một đối tượng của lớp cơ
sở. Nghĩa là tất cả các thành phần của lớp cơ sở đều tìm thấy trong lớp
dẫn xuất.

 Một đối tượng lớp cơ sở không thể thay thế một đối tượng lớp dẫn xuất.

 Ví dụ: 4.5 <Tài liệu học tập>

26
4.1. ĐƠN KẾ THỪA
 Con trỏ và kế thừa

• Tương thích giữa con trỏ lớp dẫn xuất và con trỏ lớp cơ sở :

 Một con trỏ đối tượng lớp cơ sở có thể trỏ đến một đối tượng lớp dẫn
xuất.

 Một con trỏ lớp dẫn xuất không thể trỏ đến đối tượng lớp cơ sở trừ
trường hợp ép kiểu.

 Ví dụ: 4.6 <Tài liệu học tập>

27
4.1. ĐƠN KẾ THỪA
 Con trỏ và kế thừa

• Tương thích giữa tham chiếu lớp dẫn xuất và tham chiếu lớp cơ
sở :

 Một tham chiếu đối tượng lớp cơ sở có thể tham chiếu đến một đối
tượng lớp dẫn xuất.

 Một tham chiếu lớp dẫn xuất không thể tham chiếu đến đối tượng lớp cơ
sở trừ trường hợp ép kiểu.

 Ví dụ: 4.7 <Tài liệu học tập>

28
4.1. ĐƠN KẾ THỪA
 Phạm vi truy xuất

• Khi thiết lập quan hệ kế thừa, vẫn cần phải quan tâm đến tính đóng gói
và che dấu thông tin. Vì vậy cần xác định ảnh hưởng của kế thừa đến phạm
vi truy xuất các thành phần của lớp. Hai vấn đề được đặt ra là:

- Hàm thành phần của lớp dẫn xuất có quyền truy xuất các thành phần
riêng tư của lớp cơ sở hay không.

- Các thành phần của lớp cơ sở, sau khi kế thừa xuống lớp dẫn xuất, thì
bên ngoài có quyền truy xuất đến các thành phần này thông qua đối tượng
của lớp dẫn xuất hay không.

29
4.1. ĐƠN KẾ THỪA
 Phạm vi truy xuất

• Truy xuất các thành phần của lớp cơ sở từ lớp dẫn xuất

- Thành phần public: có thể được truy xuất từ bất cứ nơi nào (từ sau khai
báo lớp).

- Thành phần private: chỉ được truy xuất bởi các hàm thành phần và các
hàm friend của lớp cơ sở. <“Phạm vi lớp” chỉ mở rộng cho “bạn bè”, mà
không được mở rộng đến các lớp “con cháu”>

- Thành phần protected: Thành phần kiểu protected giống như private,
ngoại trừ một điều là các thành phần này có thể được truy nhập từ lớp dẫn
xuất. <Đặc biệt cần chú ý là các thành phần protected không thể truy nhập
từ bên ngoài lớp cơ sở hay lớp dẫn xuất từ lớp cơ sở đó>.
30
4.1. ĐƠN KẾ THỪA
 Phạm vi truy xuất

• Nhận xét:

- Thuộc tính protected là phương tiện để tránh phải sửa đổi lớp cơ sở khi
có lớp dẫn xuất mới ra đời. Nhờ đó nó bảo đảm được tính đóng của một
lớp. Khai báo một thành phần nào có thuộc tính protected tương đương với
qui định trước tất cả các lớp con, cháu sau này đều là bạn của thành phần
đó.

- Thông thường ta dùng thuộc tính protected cho các thành phần dữ liệu
và thuộc tính public cho hàm thành phần.

31
4.1. ĐƠN KẾ THỪA
 Phạm vi truy xuất

• Tổng kết khả năng truy nhập các thành phần trong một lớp:

Truy cập public protected private

Trong cùng lớp Có Có Có

Lớp kế thừa Có Có Không

Bên ngoài lớp Có Không Không


32
4.1. ĐƠN KẾ THỪA
Các kiểu kế thừa

• Khả năng truy nhập các thành phần trong một lớp:

33
4.1. ĐƠN KẾ THỪA
Các kiểu kế thừa

• Kiểu kế thừa private:

- Lớp dẫn xuất kế thừa private từ lớp cơ sở thì


các thành phần protected và public của lớp cơ sở
trở thành private của lớp dẫn xuất. Nói cách khác
mọi thao tác của lớp cơ sở đều bị lớp con che
dấu.

- Dẫn xuất private được sử dụng trong một số


tình huống đặc biệt khi lớp dẫn xuất không khai
báo thêm các thành phần hàm mới mà chỉ định
nghĩa lại các phương thức đã có trong lớp cơ sở.
34
4.1. ĐƠN KẾ THỪA

Các kiểu kế thừa

• Kiểu kế thừa protected:

- Các thành phần public,


protected trong lớp cơ sở trở
thành các thành phần protected
trong lớp dẫn xuất.

35
4.1. ĐƠN KẾ THỪA

 Các kiểu kế thừa

• Kiểu kế thừa public:

- Lớp dẫn xuất kế thừa public từ lớp cơ


sở thì các thành phần protected của lớp
cơ sở trở thành protected của lớp dẫn
xuất, các thành phần public của lớp cơ
sở trở thành public của lớp dẫn xuất.

- Trong dẫn xuất public, các thành


phần, các hàm bạn và các đối tượng của
lớp dẫn xuất không thể truy nhập đến các
thành phần private của lớp cơ sở
36
TÓM TẮT NỘI DUNG
Đơn kế thừa

- Các khái niệm, cách khai báo và sử dụng tính kế thừa.

- Cách cài đặt một số hàm đặc biệt trong lớp như hàm tạo, hàm
tạo sao chép, hàm hủy,….

37
CÂU HỎI CUỐI CHƯƠNG
Câu 1: Giải thích sự khác nhau giữa các thành phần protected và private?

Câu 2: Hàm tạo và hàm hủy hoạt động như thế nào trong lớp kế thừa?

Câu 4: Tìm lỗi sai của đoạn chương trình sau đây
class A
{ public:
void func();
};
class B: private A
{};
main()
{ A a;
B b;
a.func();
b.func();
A *pA= &b;
B *pb= &a;
38
}
BÀI TẬP
Bài tập 1: Xây dựng lớp Người gồm có các thành phần Họ tên và Năm
sinh. Viết các phương thức của lớp như nhập, hiển thị dữ liệu.

Xây dựng lớp Thí sinh kế thừa lớp này, trong lớp Thí sinh có Số báo
danh và Điểm các môn toán, lý, hóa. Hãy xây dựng thêm các phương thức
nhập, xuất và khai báo mảng có kiểu là Thisinh để quản lý danh sách các thí
sinh. Viết chương trình với các công việc sau:

- Nhập vào một danh sách có n thí sinh

- Hiển thị danh sách thí sinh có tổng điểm ba môn tăng dần;

- Tìm một thí sinh khi biết Số báo danh.

- Thống kê xem có bao nhiêu phần trăm thí sinh đạt yêu cầu (cả ba môn
có điểm lớn hơn hoặc bằng 5). 39
BÀI TẬP
Bài tập 2:
Xây dựng lớp Sản phẩm bao gồm: Mã sản phẩm, Tên sản
phẩm, Năm sản xuất và các phương thức nhập, xuất.
Xây dựng tiếp lớp Tivi có thêm các thuộc tính Chiều dài, Chiều
rộng của màn hình. Hãy xây dựng phương thức tính diện tích của
màn hình của lớp Tivi.
Viết chương trình nhập vào các đối tượng của lớp Tivi, sau đó
sắp xếp tăng dần theo diện tích màn hình của các đối tượng này

40
ĐẠI HỌC KINH TẾ KỸ THUẬT CÔNG NGHIỆP
KHOA CÔNG NGHỆ THÔNG TIN

LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG

CHƯƠNG 4. KỸ THUẬT KẾ THỪA

4.2 Đa thừa kế
4.3 Các lớp cơ sở ảo
Năm học 2021 - 2022 41
4.2 ĐA THỪA KẾ
Khái niệm:
Đa kế thừa là cơ
chế, trong đó lớp dẫn
xuất có thể kế thừa
từ hai hay nhiều lớp
cơ sở
 Về nguyên tắc,
những gì đã đề cập
trong phần đơn kế
thừa được tổng quát
hoá cho trường hợp
đa kế thừa.
42
4.2 ĐA THỪA KẾ
 Cú pháp của một lớp kế thừa nhiều lớp cơ sở:

class <Tên_lớp_dẫn_xuất> : <Kiểu _kế thừa> <tên_lớp_cơ_sở_1>,

<Kiểu _kế thừa> <tên_lớp_cơ_sở_2>,

………………//Nội dung của lớp


};

43
4.2 ĐA THỪA KẾ
 Trong đa kế thừa, mỗi lớp cơ sở được phân cách nhau
bởi dấu phẩy “,”.
 Mỗi lớp cơ sở có thể có một kiểu dẫn xuất bởi một từ
khoá dẫn xuất khác nhau.
 Nguyên tắc truy nhập vào các thành phần lớp cơ sở
cũng hoàn toàn tương tự như trong kế thừa đơn.

44
4.2 ĐA THỪA KẾ
 Ví dụ: lớp Der kế thừa từ hai lớp Base1, Base2

class Der : public Base1, public Base2


{
…………………
}; 45
4.2 ĐA THỪA KẾ
 Một số vấn đề sau cần giải quyết khi sử dụng đa kế
thừa:
- Làm thế nào biểu thị được tính độc lập của các thành phần cùng tên bên
trong một lớp dẫn xuất?

- Các hàm thiết lập và huỷ bỏ được định nghĩa và gọi như thế nào: thứ tự,
truyền thông tin v.v.?

- Làm thế nào giải quyết tình trạng kế thừa xung đột trong đó, lớp D dẫn
xuất từ B và C, và cả hai cùng là dẫn xuất của A.

46
4.2 ĐA THỪA KẾ
 Thứ tự gọi các hàm tạo, hàm hủy:
• Thứ tự gọi các hàm tạo: Các hàm tạo của các lớp cơ sở theo thứ tự
khai báo của các lớp cơ sở trong lớp kế thừa lần lượt được gọi, sau cùng là
hàm tạo của lớp kế thừa mới được gọi. <Trong trường hợp ví dụ trên, hàm
tạo lớp Base1 được gọi trước, sau đó đến hàm tạo lớp Base2 va cuối cùng
là hàm tạo lớp Der được gọi>

• Thứ tự gọi các hàm hủy: Các hàm hủy được gọi theo thứ tự ngược lại
với cách gọi hàm tạo. <Trong ví dụ trên hàm hủy lớp Der được gọi trước, sau
đó đến hàm hủy lớp Base2, cuối cùng là hàm hủy lớp Base1 được gọi.>
47
4.2 ĐA THỪA KẾ
• Truy nhập thành phần lớp cơ sở: Giống như trong đơn kế thừa, trong
hàm thành phần của lớp dẫn xuất có thể sử dụng tất cả các hàm thành phần
public (hoặc protected) của lớp cơ sở.

• Cách gọi hàm thành phần của lớp cơ sở:

- Việc truy nhập từ đối tượng lớp dẫn xuất đến các thành phần của mỗi
lớp cơ sở được tuân theo quy tắc phạm vi tương tự như trong đơn kế thừa.

- Trong trường hợp các lớp cơ sở đều có các thành phần cùng tên, việc
truy xuất đến thành phần của lớp nào phải được chỉ rõ bằng toán tử phạm vi:
“<Tên lớp>::” đối với thành phần lớp cơ sở đó.
48
4.2 ĐA THỪA KẾ
 Toán tử phạm vi :: được sử dụng trong trường hợp trên để tránh sự nhập
nhằng, ví dụ:

Trong lớp Base1 có hàm show(), trong lớp Base2 cũng có hàm show().
Vậy trong lớp Der sẽ có 2 hàm show() của hai lớp cơ sở. Khi ở lớp Der dùng
hàm show() nào cần chỉ rõ phạm vi lớp của hàm show() đó. Chẳng hạn:

void Der :: show()


{ Base1::show(); /* Sử dụng hàm lớp Base1 */
Base2::show(); /* Sử dụng hàm lớp Base2 */
cout<<"\n c ="<<c;
} 49
4.2 ĐA THỪA KẾ

Ví dụ: <vd 4.14 Tài liệu học tập>

50
4.2 ĐA THỪA KẾ

 Chú ý: Nếu một lớp cơ sở định nghĩa một hàm tạo không tham
số (hàm mặc định) hoặc định nghĩa một hàm tạo mà mọi tham số
có giá trị ngầm định thì khi viết hàm tạo lớp dẫn xuất không nhất
thiết phải gọi lại hàm tạo này.

Ví dụ: Cho hai lớp A, B như sau:

51
4.2 ĐA THỪA KẾ
class A  Hàm tạo của lớp C kế thừa từ cơ sở A, B bắt buộc
{ phải gọi lại hàm tạo của lớp A nhưng không nhất
public: thiết phải gọi lại hàm tạo của lớp B. Lớp C và hàm
int x1; main() có thể được viết như sau:
A(int x)
{ class C: public A, public B
x1=x; { public:
}
}; int x3;
class B C(int a,int c): A(a)
{
public: {x3=c;}
int x2; };
B(int main()
x=0)
{ {C m(4,8);
x2=x;
} cout<<m.x1<<”“<<m.x2<<” “<<m.x3;
}; } 52
4.3 CÁC LỚP CƠ SỞ ẢO
Trong đa kế thừa, thường gặp tình huống một lớp cơ sở có nhiều
lớp kế thừa trực tiếp.
class A

{ ………

int v1; ……………

class B: public A{ }

class C: public A{ }

class D: public B, public C { }


53
4.3 CÁC LỚP CƠ SỞ ẢO
Lớp D kế thừa lớp A hai lần, như vậy các thành phần (hàm, dữ liệu) sẽ
xuất hiện trong D hai lần. Đối với các hàm thành phần thì vấn đề này không
quan trọng bởi chỉ có duy nhất một hàm cho một lớp cơ sở, các hàm thành
phần là chung cho mọi đối tượng của lớp. Tuy nhiên các thành phần dữ liệu
lại được lặp lại trong các đối tượng khác nhau (thành phần dữ liệu của mỗi
đối tượng là độc lập).

 Để xử lý vấn đề trên, C++ cho phép chỉ tổ hợp một lần duy nhất các
thành phần của lớp A trong lớp D nhờ việc khai báo trong các lớp B, C
rằng A là lớp cơ sở ảo.

54
4.3 CÁC LỚP CƠ SỞ ẢO
 Khai báo lớp cơ sở ảo
Trong khai báo lớp dẫn xuất bổ sung trước tên lớp kế thừa từ khóa virtual.

class A

{ ………..
int v1; ……………
}

class B: public virtual A { }

class C: public virtual A{ }

class D: public B, public C { }


55
4.3 CÁC LỚP CƠ SỞ ẢO
 Hàm tạo và hàm hủy với lớp cơ sở ảo

Thứ tự gọi các hàm tạo của các lớp cơ sở được xác định theo nguyên tắc:

- Đầu tiên các hàm tạo của các lớp cơ sở ảo sẽ được gọi theo thứ tự xuất
hiện của chúng khi khai báo lớp dẫn xuất.

- Sau khi các hàm tạo của lớp cơ sở ảo được gọi thì hàm tạo của các lớp
cơ sở khác sẽ được gọi. Thứ tự thực hiện của các hàm tạo này cũng được quyết
định bởi thứ tự khai báo của các lớp đó trong lớp dẫn xuất.

Thứ tự gọi các hàm hủy ngược lại so với hàm tạo.

56
4.3 CÁC LỚP CƠ SỞ ẢO
 Cài đặt CT <Code Ví dụ 4.17 Tài liệu học tập>

57
4.3 CÁC LỚP CƠ SỞ ẢO – TÓM TẮT NỘI DUNG
 Các nội dung chính:

 Khái niệm đa kế thừa

 Cách xây dựng lớp theo sơ đồ đa kế thừa

 Hàm tạo, hàm hủy trong đa kế thừa

 Các lớp cơ sở ảo

58
TÓM TẮT NỘI DUNG
 Các nội dung chính:

 Khái niệm đa kế thừa

 Cách xây dựng lớp theo sơ đồ đa kế thừa

 Hàm tạo, hàm hủy trong đa kế thừa

 Các lớp cơ sở ảo

59
CÂU HỎI VÀ BÀI TẬP
 Câu 1: Chỉ ra cách khai báo đối tượng có thể có mà không thực hiện hàm tạo
sao chép cho lớp dẫn xuất A2, B2, C2 dưới đây.
class A1
{
private:
A1(int i);
public:
A1(int i, int j)
};
class A2 : public A1
{
public:
A2() {}
A2(int i) : A1(i) {}
A2(int i, int j): A1(i,j) {}
};
60
CÂU HỎI VÀ BÀI TẬP
class B1
{ protected:
B1();};
class B2 : public B1
{ };
class C1
{
public:
virtual void func ()=0;
};
class C2 : public C1
{
}; 61
CÂU HỎI VÀ BÀI TẬP
Câu 2: Tìm lỗi sai của đoạn chương trình sau đây
class A{
public:
void func();
};
class B: private A
{};
main()
{ A a;
B b;
a.func();
b.func();
A *pA= &b;
B *pb= &a;
}
62
CÂU HỎI VÀ BÀI TẬP
Bài tập: Xây dựng một lớp đối tượng các máy in, lớp gồm có các thành
phần:
- Các thuộc tính số hiệu và số lượng trong kho.
- Hàm nhapkho(int q) để nhập vào kho q đơn vị mặt hàng.
- Hàm xuatkho(int q) để xuất ra khỏi kho q đơn vị mặt hàng.
Xây dựng lớp máy in laser kế thừa từ lớp máy in và có thêm thuộc tính dpi
Xây dựng lớp máy in màu kế thừa từ lớp máy in có thêm thuộc tính bảng màu.
Xây dựng lớp máy in laser màu kế thừa từ lớp máy in laser và máy in màu.
Viết chương trình hướng đối tượng quản lý các loại máy in với các thủ tục:
nhập, xuất và in ra số lượng các loại có trong kho.

63

You might also like