You are on page 1of 230

LẬP TRÌNH C++ NÂNG CAO

• rong C++, bạn có thể định dạng dữ liệu nhập xuất cho thiết bị nhập xuất chuẩn (bàn
phím, màn hình console), hoặc có thể định dạng dữ liệu nhập xuất cho file văn bản.
• Để định dạng dữ liệu, bạn cần thêm chỉ thị #include <iomanip> vào đầu chương
trình. Thư viện này chứa các toán tử định dạng (manipulator).
• Ví dụ: std::endl cũng là một manipulator thuộc <iostream> library. Bên dưới là những
manipulator khá thông dụng trong C++:
• Toán tử std::setw(n): xác định độ rộng dành cho của dữ liệu xuất. Khi sử
dụng std::setw(n), các khoảng trắng sẽ được thêm vào bên trái hoặc bên phải dữ liệu
xuất ( để tổng số ký tự là n). Dữ liệu khi in ra sẽ được canh trái hoặc canh phải.
• Toán tử std::left và std::right dùng chung với std::setw(n) để canh lề trái hoặc lề phải.
• Toán tử std::setfill(ch) dùng chung với std::setw(n) để quy định ký tự ch được thêm vào
thay vì dùng khoảng trắng mặc định. Ví dụ: nếu dùng std::setfill(‘-’) thì dấu ‘-‘ sẽ được thay
cho khoảng trắng.

2
• #include <iostream>
• #include <iomanip> // for std::setw(n), std::setfill(ch), std::left, std::right
• using namespace std;
• int main() {
• cout << "Kteam Solutions and Entertainment" << endl;
• cout << "HowKteam.com" << endl << endl;
• cout << setw(5) << left << "ID"; // độ rộng 5 ký tự, canh trái ID
• cout << setw(30) << left << "Name"; // độ rộng 30 ký tự, canh trái Name
• cout << setw(20) << right << "Address" << endl; // độ rộng 20 ký tự, canh phải Address
• cout << setfill('-'); // set fill bằng ký tự '-' thay vì ' ‘
• cout << setw(55) << "-" << endl; // fill 55 ký tự '-‘

3
• // reset fill bằng ký tự ' '
• cout << setfill(' ');
• // in thông tin theo format như trên
• cout << setw(5) << left << 1;
• cout << setw(30) << left << "Nguyen Doan Ngoc Giau";
• cout << setw(20) << right << "Sai Gon" << endl;
• cout << setw(5) << left << 2;
• cout << setw(30) << left << "Tran Kim Long";
• cout << setw(20) << right << "Da Lat" << endl;
• cout << setw(5) << left << 3;
• cout << setw(30) << left << "Nguyen Son Tung";
• cout << setw(20) << right << "Dong Nai" << endl; return 0; }

4
CHƯƠNG 1

5
1.1. Lịch sử phát triển
• Lập trình hướng đối tượng đã được phát triển như là phương pháp lập trình chủ
đạo từ giữa thập niên 1980 nguyên do đáng kể là việc ảnh hưởng của C++, một
ngôn ngữ mở rộng của C. Địa vị thống trị của OOP đã được củng cố vững chắc
bởi sự phổ biến của các GUI (Giao diện đồ họa người dùng) dành cho ngôn ngữ
lập trình hướng đối tượng ngày càng tiện lợi.

7
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Nội dung bài học


 So sá nh lậ p trình truyền thố ng và hướ ng đố i tượ ng
 Cá c khá i niệm về lớ p và đố i tượ ng:
- Đố i tượ ng
- Lớ p
- Tính trừ u tượ ng
- Tính đó ng gó i
- Tính kế thừ a
- Tính đa hình
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Lập trình truyền thống

 Phương pháp tiếp cận của lập trình truyền thống


 Lậ p trình tuyến tính.
 Lậ p trình cấ u trú c
 Ưu điểm
 Chương trình rõ rà ng, dễ hiểu, dễ theo dõ i.
 Tư duy giả i thuậ t rõ rà ng.
 Khuyết điểm
 Khô ng hỗ trợ việ c sử dụ ng lạ i mã nguồ n.
 Khi thay đổ i cấ u trú c dữ liệu, phả i thay đổ i giả i thuậ t.
 Phả i giả i quyết cá c mố i quan hệ vĩ mô giữ a cá c module phầ n
mềm trong cá c dự á n lớ n.
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Lập trình hướng đối tượng

 Lập trình hướng đối tượng (tiếng Anh:


Object-oriented programming, viết tắt:
OOP)
 OOP là đi nghiên cứu các đối tượng trong
tự nhiên rồi cố gắng nắm bắt những hành
động cùng đặc tính của chúng và biểu diễn
dưới dạng đối tượng ảo trong ngôn ngữ lập
trình
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Lập trình hướng đối tượng

 Một số ưu điểm nổi bật


 Khô ng có nguy cơ dữ liệu bị thay đổ i tự do trong
chương trình.
 Khi thay đổ i cấ u trú c dữ liệu củ a mộ t đố i tượ ng,
khô ng cầ n thay đổ i mã nguồ n củ a cá c đố i tượ ng khá c.
 Có thể sử dụ ng lạ i mã nguồ n, tiết kiệm tà i nguyên.
 Phù hợ p vớ i cá c dự á n phầ n mềm lớ n, phứ c tạ p.
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng

 Khá i niệm đối tượng (object) trong lậ p trình


hướ ng đố i tượ ng giố ng như mộ t đố i tượ ng cụ thể
trong thế giớ i thự c.
 Mỗ i đố i tượ ng có cá c thuộ c tính và cá c hà nh vi
riêng.
 Thuộc tính (attribute) mô tả đặ c điểm củ a đố i
tượ ng.
 Hà nh vi là phương thứ c hoạ t độ ng củ a đố i
tượ ng, gọ i tắ t là phương thức (method).
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Ví dụ : Phâ n số
 Đặ c điểm
 Tử số
 Mẫ u số
 Thao tá c
 Cộ ng, trừ , nhâ n, chia
 Tố i giả n
 Nghịch đả o
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Ví dụ : xe hơi
 Mà u trắ ng
 4 cử a
 4 bá nh
 Hiệu Toyota
 Chạ y tớ i
 Chạ y lui
 Xe dừ ng
…
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Đố i tượ ng:
 XeHoi  Tên đố i tượ ng
 Hiệu xe
 Mà u xe  Thuộ c tính
 Số bá nh xe
 Số cử a
 Chạ y tớ i
 Chạ y lui  Phương thứ c
 Dừ ng xe
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Lớp là mộ t khái niệm trừ u tượ ng, dù ng để chỉ mộ t
tậ p hợ p cá c đố i tượ ng có mặ t trong hệ thố ng.
 Ví dụ :
− Cá c chiếc xe Toyota, Honda, Porsche thuộ c lớ p xe
hơi.
• Cá c con chó giữ nhà , chó să n, chó kiểng thuộ c lớ p
chó .
 Lớp có thuộ c tính (property) và phương thứ c
(method):
 Thuộ c tính củ a lớ p tương ứ ng vớ i thuộ c tính củ a đố i
tượ ng.
 Phương thứ c củ a lớ p tương ứ ng vớ i cá c hà nh độ ng củ a
đố i tượ ng.
Phân biệt
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Class &
Object
Class chỉ một cái gì đó chung chung, object là một cái cụ thể

•Công thức làm bánh quy là một Class  bánh quy là một Object
•Con gái là một Class  Hồng là một Object
•Con mèo là một Class  Con mèo Mimi nhà tôi là một Object
•Bản vẽ là một Class  Ngôi nhà của tôi là một Object
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Mộ t Lớp có thể có mộ t trong cá c khả nă ng sau:
 Hoặ c chỉ có thuộ c tính, khô ng có phương thứ c.
 Hoặ c chỉ có phương thứ c, khô ng có thuộ c tính.
 Hoặ c có cả thuộ c tính và phương thứ c, trườ ng hợ p nà y
là phổ biến nhấ t.
 Lớ p khô ng có thuộ c tính và phương thứ c nà o là
cá c lớ p trừ u tượ ng. Cá c lớ p nà y khô ng có đố i
tượ ng tương ứ ng.
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 LẬ P TRÌNH HƯỚ NG ĐỐ I TƯỢ NG CÓ 4 ĐẶ C
TRƯNG:
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Tính trừ u tượ ng: (Abstraction)
 Tính trừu tượng là tính chất không thể hiện cụ
thể mà chỉ nêu tên vấn đề. Đó là một quá
trình che giấu các hoạt động bên trong và chỉ
hiển thị những tính năng thiết yếu của đối
tượng tới người dùng.
 Ví dụ: một người sử dụng điện thoại để gửi tin
nhắn thì anh ta sẽ nhập nội dung tin nhắn,
thông tin người nhận và ấn nút gửi. Khi anh ta
bắt đầu gửi tin thì anh ấy không biết những gì
diễn ra bên trong quá trình gửi mà chỉ biết
được là kết quả của tin nhắn đã được gửi đến
người nhận thành công hay chưa
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Ưu điểm khi sử dụng tính trừu tượng để lập trình:


•Tính trừu tượng cho phép các lập trình viên loại bỏ
tính chất phức tạp của đối tượng bằng cách chỉ đưa ra
các thuộc tính và phương thức cần thiết của đối tượng
trong lập trình,
•Tính trừu tượng giúp chúng ta tập trung vào những
cốt lõi cần thiết của đối tượng
•Tính trừu tượng cung cấp nhiều tính năng mở rộng
khi sử dụng kết hợp với tính đa hình và kế thừa
trong lập trình hướng đối tượng.
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Tính trừu tượng giúp chúng ta giảm sự phức
tạp. Có hai cách thực hiện tính trừu tượng như
bên dưới:
 Lớp trừu tượng (Abstract Class)
 Giao diện (Interface)
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Tính đó ng gó i:

 Đóng gói là sự che giấu bên trong dữ liệu riêng


của mỗi đối tượng của lớp được khai báo và chỉ
được truy xuất thông qua hệ thống các phương
thức có sẵn của lớp
 Tấ t cả mọ i thao tá c truy xuấ t và o thà nh phầ n dữ liệu từ đố i
tượ ng nà y qua đố i tượ ng khá c phả i đượ c thự c hiệ n bở i cá c
phương thứ c (method) củ a chính đố i tượ ng chứ a dữ liệ u.
 .
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Tính đóng gói có những đặc điểm như sau:

•Tạo ra cơ chế để ngăn ngừa việc gọi phương thức của lớp này
tác động hay truy xuất dữ liệu của đối tượng thuộc về lớp khác.
•Dữ liệu riêng (khi được khai báo là private) của mỗi đối tượng
được bảo vệ khỏi sự truy xuất không hợp lệ từ bên ngoài.
•Người lập trình có thể dựa vào cơ chế này để ngăn ngừa việc
gán giá trị không hợp lệ vào thành phần dữ liệu của mỗi đối
tượng.
•Cho phép thay đổi cấu trúc bên trong của một lớp mà không làm
ảnh hưởng đến những lớp bên ngoài có sử dụng lớp đó.
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Để cài đặt tính đóng gói, chúng ta có 2 bước như


sau:
•Khai báo các thuộc tính của đối tượng trong
lớp là private để các lớp khác không thể truy cập trực
tiếp/sửa đổi được.
•Cung cấp các phương thức getter/setter có phạm vi truy
cập là public
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Tính kế thừ a:

 Cho phép xâ y dự ng mộ t lớ p mớ i dự a trên cá c định nghĩa củ a


mộ t lớ p đã có .
 Lớ p đã có gọ i là lớ p Cha, lớ p mớ i phá t sinh gọ i là lớ p Con
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Tính kế thừ a:

 Lớ p con kế thừ a tấ t cả cá c thà nh phầ n củ a lớ p


Cha, có thể mở rộ ng cá c thà nh phầ n kế thừ a và
bổ sung thêm cá c thà nh phầ n mớ i.
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Tính kế thừ a:
Ví dụ :
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Khái niệm Lớp và Đối tượng


 Tính đa hình (polymorphism): Đa hình có
nghĩa là nhiều hình thức, trong đó
‘poly’ có nghĩa là nhiều, còn ‘morph’
có nghĩa là hình thức
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Ví dụ: Khi bạn ở trong trường học là sinh viên thì bạn có nhiệm vụ học,
nghe giảng,..., nhưng khi bạn ở nhà thì bạn lại đóng vai trò là thành viên
trong gia đình và bạn có nhiệm vụ phải làm việc nhà, rồi khi bạn vào siêu
thị thì bạn đóng vai trò là khách hàng đi mua hàng. Vì vậy, chúng ta có thể
hiểu đa hình của đối tượng là trong từng trường hợp, hoàn cảnh khác nhau
thì đối tượng có khả năng thực hiện các công việc khác nhau.
1.9. Những ngôn ngữ hỗ trợ lập trình hướng đối tượng

• Lập trình hướng đối tượng không là đặc quyền của một ngôn ngữ
nào đặc biệt.
• Những ngôn ngữ được thiết kế đặc biệt, hỗ trợ cho việc mô tả, cài
đặt các khái niệm của phương pháp hướng đối tượng được gọi
chung là ngôn ngữ hướng đối tượng.
Ví dụ: C++, Java, C#, PHP…
• Trong môn học này ta sử dụng ngôn ngữ C++ để lập trình hướng đối
tượng.

31
32
2.1. Xây dựng lớp và đối tượng
a. Khai báo lớp

class <tên_lớp>

{
[quyền truy xuất:]
//khai báo các thành phần dữ liệu (thuộc tính) của lớp
[quyền truy xuất:]
//khai báo các thành phần hàm (phương thức) của lớp
};
33
a. Khai báo

Trong đó:
<tên_lớp>

 do người dùng đặt

 tuân theo các qui tắc về tên

Ví dụ: SV, NGUOI, Hoa_Don, ps, Ma_Tran…

34/20
a. Khai báo
[quyền truy xuất:]
 Là khả năng truy xuất thành phần dữ liệu
 Ngầm định là private

private: trong phạm vi lớp đó

public: ở mọi nơi nếu đối tượng tồn tại

protected: phạm vi lớp đó và các lớp con kế thừa

35/20
a. Khai báo
Thành phần của lớp

Thuộc tính

Phương thức

36/20
a. Khai báo
Khai báo thành phần
 Thuộc tính:
Tương tự như khai báo biến

<kiểu dữ liệu > <tên_thuộc tính>;

Chú ý: không được khởi tạo giá trị ban đầu

37/20
a. Khai báo
Khai báo thành phần:
 Hàm thành viên(phương thức)
Cách 1: Khai báo ngoài lớp và định nghĩa ngoài lớp
<kiểu trả về > tên lớp::<tên_phương thức>([đối sô])
{
// <thân hàm>
}
Cách 2: Khai báo trong lớp và định nghĩa ngay trong lớp
<Kiểu trả về> <Tên phương thức>([<Các tham số>]) { …}
38/20
a. Khai báo

Ví dụ 1:
Xây dựng cấu trúc dữ liệu mô tả sinh viên:

Thuộc tính: họ tên, ngày sinh, giới tính, Điểm toán, lý, hóa, Đtb

Phương thức: nhập, tính đtb, in

 Lớp sinh viên

39/20
a. Khai báo

Ví dụ 2:
Xây dựng cấu trúc dữ liệu mô tả các hóa đơn:
Thuộc tính: mã vật tư, tên vật tư, loại phiếu, ngày lập, khối
lượng, đơn giá, thành tiền…

Phương thức: nhập, tính thành tiền, in

 Lớp các hóa đơn

40/20
a. Khai báo

Ví dụ 3:
Xây dựng cấu trúc dữ liệu mô tả các phân số:

Thuộc tính: tử số, mẫu số

Phương thức: nhập, tối giản, in

 Lớp các phân số

41/20
Ví dụ: Khai báo phương thức bên ngoài lớp
class Car
{
private:
int tocdo ;
char nhanhieu[20];
public:
void show();
};
void Car::show()
{
cout << “day la ” << nhanhieu << “ co toc do ” << tocdo << “km/h!” << “\n”;
return;
}

42
Ví dụ :Khai báo phương thức bên trong lớp
class Car
{
private:
int tocdo ;
char nhanhieu [20];
public:
void show()
{ // Khai báo phương thức ngay trong lớp
cout << “Day la ” << nhanhieu << “ co toc do” << tocdo << “km/h!” << “\n”;
return;
}
};

43
b. Khai báo đối tượng (sử dụng lớp đối tượng)

Cú pháp:
<tên_lớp> <tên_đối_tượng>;

Ví dụ: khai báo 2 đối tượng sinh viên

SV sv1, sv2;

Khi đó sv1, sv2 là hai đối tượng sinh viên

44/20
c. Truy xuất thành phần

Thuộc tính:
<tên_đối_tượng>.<tên_thuộc tính>;

Ví dụ: truy xuất họ tên và ngày sinh của sv

sv1.ht;
sv2.ns;
Nếu là con trỏ: <tên_con_trỏ>-><tên_thuộc tính>;

45/20
c. Truy xuất thành phần

Thành phần hàm (phương thức)

<tên_đối_tượng>.<tên_hàm>([ds đối số]);

Ví dụ: truy xuất phương thức nhập và in của sv

sv1.nhap();
sv2.in();

Với con trỏ: <tên_con_trỏ>->.<tên_hàm>([đối số]);

46/20
2.2. Mảng và con trỏ đối tượng
Mảng đối tượng
Khi cần khai báo một dãy các đối tượng cùng loại ta có
thể sử dụng mảng đối tượng, cách khai báo và sử dụng giống
mảng thông thường.

Khai báo: <tên_lớp> <tên_mảng>[spt];

Ví dụ: SV sinhvien[50]; PS a[8];

47
Con trỏ đối tượng
Khi cần cấp phát dữ liệu động ta có thể khai báo
con trỏ đối tượng theo cú pháp sau:

<tên_lớp> *<tên_con_trỏ>;

Ví dụ: SV *p = sinhvien;
•Giải phóng đối tượng qua thao tác Delete: Delete <Tên đối tượng con trỏ>
•VD: delete p;

48
RKING HARD & SMART TODAY FOR A BETTER TOMORROW

Toán tử new
• Mọi đối tượng phải được tạo b ằng toán tử new:
• Cấp phát vùng nhớ động
• Ví dụ:
• Student *a;//a chưa trỏ vào đâu a->null
• a=new Student[20];// a được tr ỏ vào bộ nhớ m ảng có kiểu student đ ược sinh ra t ừ t ừ khóa new
Khai báo mảng động với con trỏ:
Cú pháp:
<Tên lớp> * <Tên biến mảng động> = new <Tên lớp> [<độ dài mảng>]
Ví dụ: Đã khai báo lớp sinhvien
khai báo 1 mảng gồm n sinh viên
Sinhvien * sv = new sinhvien[n];
Giải phóng bộ nhớ
Delete [] <tên biến mảng động>;
VD: delete [] sv;

50
 class date Ví dụ 1:
{ Nhìn vào đoạn code trên cho
public:
biết:
int day;
int month; Lớp?
int year; Thuộc tính?
}; Gõ chương trình xem kết quả
int main() Thay public thành private
{ kết quả?
date today;
today.day = 25;
today.month = 12;
today.year = 2014;
cout << “\n Ngay la “<< today.day<< “/” ;
cout << today.month << “/” <<today.year << endl;
return 0;
}
51
Bài tập- phân tích
Bài 1. Xem xét bài toán
Nhập vào danh sách sinh viên gồm n sinh viên với những thông tin:
•Họ và tên
•Ngày sinh
•Giới tính
• Địa chỉ
• Lớp
•hiển thị thông tin theo ngày sinh tăng dần.
Phân tích bài toán sử dụng phương pháp trừu tượng hóa dữ liệu cho biết bài toán
gồm những đối tượng nào, thuộc tính và hành vi của chúng.

52
Phân tích bài toán 1:
Như vậy bài toán trên gồm 2 đối tượng là: sinh viên và danh sách sinh viên
- Đối tượng sinh viên gồm:
Các thuộc tính: Họ và tên, Ngày sinh, giới tính, Địa chỉ, Lớp
Các phương thức: Nhập thông tin sinh viên, Hiển thị thông tin sinh
viên
- Đối tượng danh sách sinh viên gồm:
Các thuộc tính: Số sinh viên, vùng dữ liệu lưu thông tin các sinh viên
(mảng)
Các phương thức: Nhập thông tin danh sách sinh viên, Hiển thị thông
tin danh sách sinh viên, Sắp xếp danh sách sinh viên theo ngày sinh tăng dần.

53
Bài 2: Xem xét bài toán
Người ta quản lý thông tin công dân gồm các thông tin họ
tên, ngày sinh, giới tính, địa chỉ, số chứng minh. Bộ phận
quản lý đăng ký kết hôn luôn cần xác định điều kiện kết hôn
của hai công dân bất kỳ (giả sử điều kiện kết hôn là: không
cùng giới tính, nam từ 20 tuổi , nữ từ 18 tuổi trở nên, tình
trạng hồn nhân là độc thân). Hãy xác định các thuộc tính và
phương thức cần xây dựng cho lớp công_ dân_kết_hôn để
đáp ứng chức năng của bộ phận quản lý đăng ký kết hôn
54
Phân tích bài 2:
- Các thuộc tính cần khai báo:
Họ tên
Ngày sinh
Giới tính
Địa chỉ
Số chứng minh
Tình trạng hôn nhân
- Các phương thức cần xây dựng:
Nhập thông tin
Hiển thị thông tin
Tìm kiếm thông tin
Kiểm tra điều kiện kết hôn của hai công dân bất kỳ.
55
Bài 3: Xét bài toán:
Người ta cần đưa phân số vào máy tính để quản lý nhằm nâng cao hiệu
quả xử lý tính toán cho một bài toán phức tạp khác. Một bạn sinh viên
đã lấy một vài ví dụ về phân số như:
•Bạn sinh viên nhận thấy rằng mỗi phân số được xác định bằng cách
đưa một giá trị tử số, một giá trị mẫu số. Đồng thời cũng nghiên cứu
được rằng với phân số các phép toán hay thực hiện là: +, -, *, /, rút
gọn…
•Hãy cùng phân tích bài toán và cho biết bài toán quản lý phân số gồm
các lớp đối tượng nào các thuộc tính và phương thức.

56
Phân tích bài toán 3
Lớp phân số
Thuộc tính: Tử số, mẫu số,
Phương thức:
•Nhập tử số, mẫu số
•Tối giản phân số
•Cộng phân số
•Trừ phân số
•Nhân phân số
•Chia phân số
•In kết quar

57
Bài tập buổi 2
Bài 1: Xây dựng lớp Điểm trong hệ trục tọa độ xOy gồm hoành
độ và tung độ; Xây dựng các phương thức nhập điểm, hiển thị
điểm. Phân tích và cài đặt theo C++
Phân tích:
-Xây dựng: Lớp điểm (khai báo)
-Thuộc tính: tọa độ x (hoành độ), tọa độ y (tung độ)
-Phương thức: Nhập tọa độ, In tọa độ

58
Code bài 1:
class Diem
{
double x; //Khai báo hoành độ
double y; //Khai báo tung độ
public: // Khai báo Phương thức
int nhapd()
{ // Xay dung phuong thuc nhâp ben
cout<< "\n Nhap vao hoanh do cua diem:"; trong lop
cin>>x;
cout<< "\n Nhap vao tung do cua diem:";
cin>>y;
return 0;
}
//Khai bao phuong thuc hien thi diem
void hienthi();
};
//Xay dung phuong thuc hien thi diem ben ngoai lop
void Diem::hienthi()
{ //Xay dung phuong thuc hien thi diem
cout<< "("<<x<< ","<< y<< ")"; ben ngoai lop
}
59
// chuong trinh chinh
main()
{
Diem A; // Khai báo đối tượng A kiểu lớp điểm
A.nhapd(); // Truy xuất phương thức Nhập
cout<< "\n Toa do diem A:";
A.hienthi(); (); // Truy xuất phương thức hiển thị
getch();
}

60
Bài tập buổi 2
Bài 2: Xây dựng lớp sinh viên gồm các thuộc tính họ và tên,
lớp, ngày sinh, giới tính, địa chỉ, điểm trung bình. Nhập vào
thông tin sinh viên và hiển thị thông tin sinh viên.
Hãy Phân tích và cài đặt C++ (tự làm)

61
Bài 3: Nhập vào danh sách sinh viên gồm n sinh viên bao gồm
bao gồm: Mã sinh viên, Họ tên và Điểm các môn học: Toán,
Lý, Hóa.
Yêu cầu: Hiển thị danh sách vừa nhập trong đó có thêm
thông tin (Trường) Tổng điểm của 3 môn học. Hiển thị danh
sách trên theo chiều giảm dần của Tổng điểm.
Hãy Phân tích và cài đặt C++
Chú ý: Bài phân tích giống bài phân tích 1 ở phần lý thuyết

62
Bài 4: Nhập vào danh sách sinh viên gồm n sinh viên bao gồm: Mã sinh
viên, Họ và tên, Giới tính, Ngày tháng năm sinh và Điểm các môn học:
Tiếng Anh, Mạng máy tính, Ngôn ngữ lập trình C, Cấu trúc dữ liệu và
giải thuật, Lập trình web.
Yêu cầu:
Hiển thị danh sách vừa nhập
Hiển thị danh sách các sinh viên có đủ điều kiện dự thi tốt nghiệp (ĐK
dự thi là điểm trung bình các môn học >=5.0 và không có điểm nào
dưới 5.0).
Hãy Phân tích và cài đặt C++

63
Bài tập về nhà- Phân tích- Buổi 2
Bài 1:
Người ta cần quản lý thông tin về thành phố của các quốc gia. Mỗi quốc gia người ta
cần quản lý các thông tin: tên quốc gia, vị trí địa lý, tên thủ đô, số thành phố trực
thuộc quốc gia. Với mỗi thành phố người ta quản lý các thông tin như: tên thành
phố, vị trí địa lý, số dân. Hệ thống cho phép nhập vào thông tin quốc gia, thông tin
thành phố và cũng cho phép hiển thị các thông tin khi cần thiết, tìm kiếm tên thủ đô
của quốc gia.
•Hãy phân tích bài toán và cho biết các lớp đối tượng cần xây dựng cùng thuộc tính
và phương thức của chúng.

64
Bài tập về nhà- Phân tích- Buổi 2
Bài 2:
Để bảo vệ độc lập chủ quyền và lãnh thổ quốc gia, hàng năm các
quốc gia đều duy trình công việc triệu tập các công dân nam giới tuổi
từ 18-25 nhập ngũ nếu không đang thao học tại các trường địa học,
cao đẳng, trung học chuyên nghiệp và hội đủ điều kiện về sức khỏe
(sứ khỏe tốt). Hãy xác định lớp đối tượng cần xây dựng gồm những
thuộc tính và những phương thức cần thiết nào để có thể xác định
điều kiện nhập ngũ từ đó đưa ra giấy báo nhập ngũ.

65
Bài tập về nhà- Phân tích- Buổi 2
Bài 3: Nhập vào một ma trận kích thước m*n. In ra màn hình ma
trận vừa nhập và giá trị lớn nhất của ma trận. Hãy Phân tích và cài
đặt C++
Bài 4: Xét bài toán: Nhập vào một ma trận kích thước m*n. Yêu cầu:
In ra màn hình ma trận vừa nhập
In ra màn hình danh sách các số nguyên tố có mặt trong ma trận
Sắp xếp dãy số đó theo chiều tăng dần
Hãy Phân tích và cài đặt C++

66
Code bài 3- phần bài tập
class Sinhvien
{
private:
int n; Khai báo thuộc
tính
char MaSV[10],Hoten[25];
float Dtoan, Dly, Dhoa, Tong;
public:
int NhapDL();
Khai báo phương thức
int HienthiDL();
int HienthiDiemgiam();
};

Sinhvien x,TH17[80]; // Khai báo biến đối tượng

67
int Sinhvien:: NhapDL()
{
int i;
cout<<"Nhap so sinh vien cua lop: ";
cin>>n;
for (i=1; i<=n; i++)
{
cout << "Nhap thong tin cua sinh vien thu " << i;
cin.ignore(1);
cout << "\nMaSV: " ; cin.getline(x.MaSV, 10);
cout << "Ho ten: " ; cin.getline(x.Hoten, 25);
cout << "Diem Toan: " ; cin >> x.Dtoan ;
cout << "Diem Ly: " ; cin >> x.Dly ;
cout << "Diem Hoa: " ; cin >> x.Dhoa ;
x.Tong=x.Dtoan+x.Dly+x.Dhoa;
TH17[i]=x;
}
}
68
int Sinhvien::HienthiDL()
{ /////* Hien thi thong tin cua tung sinh vien *//
int i; for (i=1; i<=n; i++)
{
cout<<"Thong tin ve nhung sinh vien da nhap: x=TH17[i];
\n"; cout <<x.MaSV<<setw(10-
///////////* Trinh bay dong tieu de *////////////// strlen(x.MaSV))<<" ";
cout <<x.Hoten<<setw(25-
cout<<"MaSV"<<setw(10-strlen("MaSV"))<<""; strlen(x.Hoten))<<"\t";
cout<<"HoTen"<<setw(25- cout <<x.Dtoan<<"\t";
strlen("HoTen"))<<"\t"; cout <<x.Dly<<"\t";
cout <<x.Dhoa<<"\t";
cout <<"Dtoan"<<"\t";
cout <<x.Tong<<"\t";
cout <<"Dly"<<"\t"; cout<<"\n";
cout <<"Dhoa"<<"\t"; }
cout <<"Tong"<<"\t"; return 0;
}
cout<<"\n";

69
int Sinhvien::HienthiDiemgiam()
// Viet ra dong tieu de
{ cout <<"MaSV"<<setw(10-strlen("MaSV"))<<"";
int i,j; cout <<"HoTen"<<setw(25-strlen("HoTen"))<<"\t";
cout <<"Dtoan"<<"\t";
for (i=1;i<=n-1;i++) cout <<"Dly"<<"\t";
for (j=i+1;j<=n;j++) cout <<"Dhoa"<<"\t";
cout <<"Tong"<<"\t";
if (TH17[i].Tong <TH17[j].Tong) cout<<"\n";
{ for (i=1; i<=n; i++)
{
x=TH17[i]; x=TH17[i];
TH17[i]=TH17[j]; cout <<x.MaSV<<setw(10-strlen(x.MaSV))<<" ";
cout <<x.Hoten<<setw(25-strlen(x.Hoten))<<"\t";
TH17[j]=x; cout <<x.Dtoan<<"\t";
} cout <<x.Dly<<"\t";
cout <<x.Dhoa<<"\t";
cout <<x.Tong<<"\t";
cout<<"Danh sach nhung sinh vien co Tong cout<<"\n";
}
diem theo chieu giam dan: \n";
return 0;
}

70
int main() // Chương trình chính
{
x.NhapDL();
x.HienthiDL();
x.HienthiDiemgiam();
system("pause");
return 0;

71
CHƯƠNG 2

72
Nội dung học buổi 3
2.3. Các phương thức
2.3.1. Phương thức tạo
2.3.2. Phương thức hủy
2.3.3. Con trỏ this
2.3.4. Phương thức getter, setter
3. Hàm bạn và lớp bạn
3.1. Hàm bạn
3.2. Lớp bạn

73
2.3. Các phương thức

2.3.1. Phương thức (hàm) tạo (Constructor)

2.3.2. Phương thức (hàm) hủy (Destructor)

2.3.3. Con trỏ This

2.3.4. phương thức getter, setter

74
2.3.1. Hàm tạo (Constructor)
a. Định nghĩa:
- Hàm tạo là một phương thức của lớp, dùng để tạo dựng một đối
tượng mới.
- Chương trình dịch sẽ cấp phát bộ nhớ cho đối tượng sau đó sẽ
gọi đến hàm tạ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à có
thể thực hiện một số công việc khác nhằm chuẩn bị cho đối tượng
mới.

75
b. Khai báo hàm tạo

<tên_lớp>([ds tham số]);


Định nghĩa ngoài lớp:

<tên_lớp>::<tên_lớp>([ds tham số])


{
//thân hàm
}
76/20
Trong đó:
 Hàm tạo phải được khai báo bên trong lớp
 Hàm khởi tạo phải có tên trùng với tên của lớp
 Không khai báo kiểu cho hàm tạo.
 Không có giá trị trả về
 Hàm khởi tạo có tính chất public
 Hàm tạo có thể có đối hoặc không có đối.
 Nếu không xây dựng thì chương trình tự động sinh hàm khởi tạo
mặc định.
 Trong một lớp có thể có nhiều hàm tạo (cùng tên nhưng khác bộ
đối).
77/20
class Car
{
int TD; char NH[20]; float G;
public:
Car(int todo, char nhanhieu[], float gia) // hàm tạo định nghĩa trong
lớp
{ TD = todo;
strcpy(NH, nhanhieu);
G = gia;
}
};
78
c. Phân loại hàm tạo

79/20
Khai báo khởi tạo sao chép:

<tên_lớp>(const <tên_lớp> &<tên_tham_số>)


Đối tượng mới sẽ là bản sao của đối tượng đã có
diem (const diem &A) // Hàm tạo sao chép
{
x=A.x;
y=A.y;
}

80/20
d. Hàm tạo có đối số mặc định
Tên_lớp(KDL thamso1=gtr1, KDL thamso2=gtr2…)
{
// nội dung
}
Ví dụ
diem (int x1=0, int y1=0) //hàm tạo có đối số mặc định
{
x=x1;
y=y1;
}
81
Ví dụ 1:
Nhập vào tọa độ 2 điểm x và y và một màu, hãy in tọa độ x,y
và màu điểm có sử dụng hàm tạo không đối số, có đối số và
sao chép.
Phân tích:
-Lớp: diem
-Thuộc tính: int x,y,m;
-Phương thức: Hàm tạo không tham số, có tham số, sao chép,
in dữ liệu

82
83
2.3.2. Hàm hủy - Destructor
- Nếu trong lớp không định nghĩa hàm hủy thì một hàm hủy mặc định
không làm gì cả được phát sinh. Đối với nhiều lớp thì hàm hủy mặc
định là đủ và không cần đưa vào một hàm hủy mới.

Khai báo:

~<tên_lớp>();
Chức năng:
- Hủy bỏ, giải phóng các đối tượng khi nó hết phạm vi tồn tại

84/20
Ví dụ: Khai báo và định nghĩa hàm hủy

Hàm hủy được khai báo và định nghĩa trong lớp

85
Như vậy hàm hủy:
Trùng tên với lớp và có dấu ~ ở trước
Mỗi lớp có duy nhất một hàm hủy
Không có đối số
Không có giá trị trả về
Không định nghĩa lại
Thực hiện một số công việc trước khi hệ thống giải phóng
bộ nhớ.
Hàm khởi tạo có tính chất public
Chương trình dịch tự động sinh hàm hủy mặc định 86/20
Ví dụ 2
Nhập vào tọa độ 2 điểm x và y và một màu, hãy in tọa độ x,y và màu
điểm có sử dụng hàm tạo không đối số, có đối số và sao chép, hàm
hủy
Phân tích:
-Lớp: diem
-Thuộc tính: int x,y,m;
-Phương thức: Hàm tạo không tham số, có tham số, sao chép, in dữ
liệu, hàm hủy

87
2.3.3. Con trỏ this
 Con trỏ this là con trỏ trỏ đến đối tượng đang gọi hàm (phương thức), tồ n tạ i
ngầ m trong mỗ i lớ P
• Cho phép truy xuất các thành phần của đối tượng đang gọi hàm thành phần
thông qua con trỏ this

88
89
2.3.4. Phương thức getter, setter
 Ta cầ n xây dự ng cá c getter/setter để truy suấ t giá trị cá c thuộ c tính (vì thuộ c
tính có phạ m vi truy xuấ t private)
 Set: truyề n giá trị và o cho biến
 Get: lấy giá trị củ a biến Ví dụ 1: class SinhVien {
private:
string hoTen;
double diem;
public void setHoTen(string hoTen)
{
this->hoTen=hoTen;
}
public string getHoTen()
{
return this->hoTen;
}
} 90
2.3.4. Phương thức getter, setter
• #include <iostream>     // Getter
using namespace std;     int getSalary() {
      return salary;
class Employee {
    }
  private:
};
    // Private attribute
    int salary;
int main() {

  public:
  Employee myObj;
    // Setter   myObj.setSalary(50000);
    void setSalary(int s) {   cout << myObj.getSalary();
      salary = s;}   return 0;
    }
91
3. Hàm bạn và lớp bạn
3.1. Hàm bạn
-Hàm bạn của lớp là hàm được khai báo bên trong lớp bắt
đầu bằng từ khóa friend.
-Được xây dựng bên ngoài lớp.
-Được phép truy cập vào bất cứ thành viên private hoặc
protected nào của lớp. Hàm bạn không phải là hàm thành
viên của lớp
-Một hàm có thể là bạn của nhiều lớp.
-Hàm bạn không phải phương thức của lớp
92
Khai báo hàm bạn
class <Tên lớp>
{
... // Khai báo các thành phần lớp như thông thường
// Khai báo hàm bạn
friend <Kiểu trả về> <Tên hàm bạn>([<Các tham số>]);
};

93
Ví dụ - khai báo

94
3.2. Lớp bạn
Định nghĩa:
• Nế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 khác. Cũng có
thể khai báo A là bạn của B và B là bạn của A.
• Một lớp có thể là bạn của vô số lớp.

95
Cách khai báo lớp bạn
Giả sử có 3 lớp A, B và C. Để khai báo
lớp này là bạn của lớp kia, ta viết theo {
mẫu sau: ...
// Khai báo trước các lớp friend class A ; // Lớp A là bạn của B
class A; friend class C ; // Lớp C là bạn của B
class B ; ...
class C; };
// Định nghĩa các lớp class C
class A {
{ ...
... friend class B ; // Lớp B là bạn của C
friend class B ; // Lớp B là bạn của A ...
friend class C ; // Lớp C là bạn của A };
...
};
class B

Chú ý: quan hệ bạn chỉ là quan hệ hai chiều khi mà khai báo bạn ở cả hai lớp.
96
Bài tập buổi 3
Bài 1: Hãy xây dựng một lớp Car gồm: Tốc độ, nhãn hiệu, giá xe. Hiện
thị thông tin về chiếc xe đó. Có sử dụng phương thức khởi tạo không
tham số, có tham số
Phân tích:
- Lớp oto
-Thuộc tính: Tốc độ, nhãn hiệu, giá xe
-Phương thức: khởi tạo không tham số, có tham số
Bài 2: Hãy nhập chiều dài và chiều rộng để tính diện tích hình chữ
nhật= chiều dài* chiều rộng (chú ý: khởi tạo không đối, đối số được
đưa vào, có sử dụng hàm hủy)
97
Bài tập buổi 3
Bài 3: Nhập vào danh sách sinh viên gồm n sinh viên bao
gồm bao gồm: Mã sinh viên, Họ tên và Điểm các môn học:
Toán, Lý, Hóa.
Yêu cầu: Hiển thị danh sách vừa nhập trong đó có thêm
thông tin (Trường) Tổng điểm của 3 môn học. Hiển thị danh
sách trên theo chiều giảm dần của Tổng điểm.
Chú ý: Khởi tạo không đối số, có đối số, sao chép, hàm hủy

98
code

99
100
CHƯƠNG 2

101
Nội dung học buổi 4

4. Khả năng nạp chồng


4.1. Chồng hàm
4.2. Chồng phương thức
4.3. Chồng toán tử
5. Lớp bao
Kiểm tra

102
4.1. Chồng hàm
Định nghĩa:
Là khả năng các hàm có thể trùng tên nhau nhưng khác
nhau về:
•Kiểu dữ liệu trả về
•Kiểu dữ liệu của tham số
•Số lượng tham số truyền vào.

103
Ví dụ 1:

104
4.1. Chồng hàm

105
Nhận xét:
Khả năng chương trình cho phép các hàm trùng tên
nhưng khác nhau về kiểu dữ liệu trả về, tham số truyền
vào, số lượng tham số truyền gọi là khả năng chồng
hàm.
- Chính vì khả năng này, khi kế thừa các lớp có sẵn ta
không còn sợ sự trùng tên không cho phép như ở một
số ngôn ngữ: PASCAL, VISUAL Basic…
106
4.2. Chồng phương thức (Overloading method)

Chồng các phương thức


(overloading method): cùng 1
tên, cùng lớp nhưng khác nhau về
danh sách tham số (khác về kiểu
dữ liệu, khá nhau về số lượng
tham số.

107
Ví dụ 2
Tính diện tích hình vuông, tính diện tích hình hình chữ nhật, tính diện tích
hình tam giác.
Diện tích hình vuông= a*a
Diện tích hình chữ nhật=a*b
Diện tích hình tam giác= sqrt(p(p-a)(p-b)(p-c) trong đó p=(a+b+c)/2
Như vây:
Ba phương thức trên đều tên là dientich sao cho, nếu như
Có 1 tham số truyền vào, nó sẽ tự hiểu là cần tính diện tích hình vuông
Có 2 tham số truyền vào, nó tự hiểu là tính diện tích hình chữ nhật
Có 3 tham số truyền vào, nó tự hiểu là tính diện tích hình tam giác.

108
109
4.3. Nạp chồng toán tử

Định nghĩa chồng toán tử (overloading)


-Là khả năng một toán tử có thể thực hiện việc
tính toán ứng với nhiều kiểu dữ liệu khác nhau.
-Các toán tử có thể được định nghĩa chồng như
một phương thức của lớp hoặc như hàm bạn của
lớp.
110
void main() void main()
{ {
float a,b,c;
int a,b,c;
c=a+b;
c=a+b;
}
}

Cùng toán tử + thực hiện cộng được kiểu dữ liệu số


thực, lẫn kiểu dữ liệu số nguyên.

111
Chú ý:
Khi nào các toán tử có thể được định nghĩa chồng như một phương thức của
lớp hoặc như hàm bạn của lớp.
- Nếu toán tử chỉ lầm việc với các đối tượng cùng một lớp thì định nghĩa là
phương thức hay hàm bạn đều được
- Nhưng nếu toán tử làm việc với các đối tượng thuộc nhiều lớp khác nhau thì
bắt buộc phải là hàm bạn.
Một số trường hợp cụ thể cần lưu ý:
+ Toán tử =,[] phải được định nghĩa là phương thức của lớp
+ Toán tử <<,>> phải được định nghĩa là hàm bạn
+ Các toán tử ++, -- có thể được sử dụng theo 2 cách khác nhau (tiền tố và hậu
tố) đòi hỏi hai hàm toán tử khác nhau.
112
Cách xây dựng chồng toán tử
<Kieu du lieu> operator toán_tử([Tham số])
{
//Nội dung
}
Ví dụ: Xây dựng phương thức toán tử + cho lớp
phân số.
113
Trước đây Bây giờ
class PS class PS
{ {
private: private:
int ts,ms; int ts,ms;
public:
public:
void nhap();
void nhap();
void xuat();
void xuat(); PS operator+(PS P);
PS cong(PS P); }; //lop PS
}; /lop PS
114
PS PS::Cong(PS P) PS PS::operator+(PS P)
{ {
PS k; PS k;
k.ts=ts*P.ms+ms*P.ts; k.ts=ts*P.ms+ms*P.ts;
k.ms=ms*P.ms; k.ms=ms*P.ms;
return k; return k;
} }
Void main() Void main()
{ PS A,B,C; {PS A,B,C;
A.nhap();B.nhap(); A.nhap();B.nhap();
C=A.Cong(B); C=A+B;
} }

Khai báo phương thức toán tử ++ và định nghĩa ngoài lớp


115
Toán tử chồng ++,--
Khi sử dụng phép toán ++,-- có thể sử dụng theo cách khác nhau
(tiền tố và hậu tố) nên đòi hỏi phải có hai cách khác nhau:
+ Dạng tiền tố:
operator++()
operator--()
+ Dạng hậu tố sử dụng thêm đối giả int:
operator++(int)
operator--(int)

116
Toán tử chồng nhập, xuất
Riêng đối với toán tử <<, >> ta không thể xây
dựng dưới dạng toán tử thông thường:
- Không thể là phương thức toán tử của lớp.
- Không thể là hàm toán tử thông thường.
- Khai báo toán tử nhập xuất phải khai báo là
hàm bạn của lớp.
Toán tử xuất dữ liệu (<<)
ostream &operator<<(ostream &os, kiểu dữ liệu bien)
{
//Cac cau lenh xuat du lieu
return os;
}
Ví dụ: ostream& operator<< (ostream& os, PS p) {}

118
Toán tử nhập dữ liệu (>>)
istream & operator>>(istream &is, kieu du lieu &bien)
{
//Cac cau lenh xuat du lieu
return is;
}
Ví du: istream& operator>>(istream& is,PS &p) {}
Ví dụ 3: Xây dựng toán tử nhập- xuất cho lớp phân số
Trước đây Bây giờ
class PS class PS
{ { Toán tử nhập
private: private:
int ts,ms; int ts,ms;
public: public:
void nhap(); friend istream &operator>>(istream &is, PS &P);
void xuat(); friend ostream &operator<<(ostream &os, PS P);
};//lop PS };//lop PS
void PS::nhap() istream &operator>>(istream &is, PS &P)
{ {
cout<<“ts=“;cin>>ts; cout<<“ts=“;is>>P.ts;
cout<<“ms=“;cin>>ms; cout<<“ms=“;is>>P.ms;
} return is;
}

120
Ví dụ 3: Xây dựng toán tử nhập- xuất cho lớp phân số
Trước đây Bây giờ
void PS::xuat() ostream &operator<<(ostream &os, PS P)
{ {
cout<<ts<<“/”<<ms; os<<P.ts<<“/”<<P.ms;
} return os; Toán tử xuất
}
void main() void main()
{ {
PS A;
A.nhap();
PS A;
A.xuat(); cin>>A;
getch(); cout<<A;
} getch();
}

121
5. Lớp bao
5.1. Định nghĩa
Một lớp có thuộc tính là đối tượng của lớp khác gọi là lớp bao.

class A class C Trong ví dụ:


{ {
private: -C là lớp bao
int a, b; private:
... int m, n; -A, B là các lớp thành phần (của C)
}; A u;
class B B p, q;
{
private: ...
double x, y, z; } ; Chú ý: Trong các phương thức của lớp bao không
... cho phép truy nhập trực tiếp đến các thuộc tính
}; của các đối tượng của các lớp thành phần.
122
5.2. Xây dựng hàm tạo cho lớp bao
Ví dụ khi xây dựng hàm tạo của lớp C, cần dùng các hàm tạo của lớp A
để khởi gán cho đối tượng thành phần u và dùng các hàm tạo của lớp B để
khởi gán cho các đối tượng thành phần p, q.
Cú pháp:
tên_lớp(danh sách đối) : tên_đối_tượng( danh sách giá trị), ...,tên_đối_tượng(
danh sách giá trị)
{
// Các câu lệnh trong thân hàm tạo
}
class A class B class C // lớp bao
{ { {
private: private: private:
double x, y, z; int m, n;
int a, b; public:
public: A u, v;
B() B p, q, r;
{
public:
A() x = y = z = 0.0 ;
} C(int m1, int n1,int a1, int b1,
{ B(double x1, double y1) double x1, double y1, double x2,
a=b=0; { double y2, double z2) : u(),
} x = x1; y = y1; z = 0.0 ; v(a1,b1), q(x1,y1), r(x2,y2,z2)
A(int a1, int b1) } {
B(double x1, double y1, m = m1 ; n = n1;
{ double z1) }
a = a1; b = b1; { };
} x = x1; y = y1; z = z1 ;
... }
...
}; };
Bài tập buổi 4
Bài 1: Hãy xây dựng lại lớp lớp phân số +, -, *, /
Bài 2: Hãy xây dựng lại lớp số phức, với các toán tử chồng: +, -, *,/
Bài 3: Hãy xây dựng lại lớp số phức, với các toán tử <<,>>
Bài 4: Hãy xây dựng lại lớp phân số, với các toán tử <<,>>
Cộng 2 số phức: (2+3i) + (5+3i) = 7+6i
Trừ 2 số phức: (2+i) -(4+3i) = -2-2i
Nhân 2 số phức: (1+2i)*(3+5i)
=1.3-2.5+(1.5+2.3)i = -7+11i

125
Kiểm tra
Phần 1: Lý thuyết
Phần 2: Thực hành

126
CHƯƠNG 3

127
Nội dung học buổi 5

3.1.Tổng quát hoá và đặc biệt hóa


3.2. Khái niệm kế thừa
3.3. Xây dựng lớp dẫn xuất
3.4. Quyền truy xuất
3.5. Định nghĩa lại quyền truy xuất

128
3.1.Tổng quát hoát và đặc biệt hóa
Khái niệm Tổng quát hóa và đặc biệt hóa là khái niệm rất tự nhiên và thông
dụng trong thế giới thực.
Rất nhiều lớp đối tượng trong thế giới thực là đặc biệt hóa hay tổng quát hóa
của đối tượng khác.
Ví dụ:
-Hình chữ nhật là một trường hợp đặc biệt của hình bình hành; mặt khác hình
chữ nhật lại là khái niệm tổng quát của hình vuông đồng thời hình vuông cũng là
trường hợp đặc biệt của hình chữ nhật.
-Hình vuông có tất cả các tính chất của hình chữ nhật bởi vì hình chữ nhật là
tổng quát hóa của hình vuông; hình vuông có tính chất đặc biệt mà hình chữ
nhật không có bởi vì hình vuông được đặc biệt hóa từ hình chữ nhật
129
Cả 3 lớp trên đều có biến và hàm giống hệt nhau về nội dung.
Tạo ra một lớp Nguoi có chứa thông tin chung để sử dụng lại
130
3.2. Khái niệm kế thừa (Inheritance)
• Kế thừa là Cho phép xây dự ng mộ t lớ p mớ i dự a trên cá c định
nghĩa củ a mộ t lớ p đã có .
Lớp đã có: Lớp mẹ hay lớp cơ sở (base class)
Lớp mới: Lớp con hay lớp dẫn xuất (derived class)

131
Có tác dụng:
• Sử dụng lại code
• Giảm số code cần
thiết
• Dễ bảo trì, sửa đổi
về sau
• Rõ ràng hơn về mặt
logic trong thiết kế
chương trình
132
133
Ví dụ 1: Xây dựng lớp PS1 {ts, ms, nhập, in, tối giản}
Lớp PS2 {ts, ms, nhập, in, tối giản, cộng, trừ, nhân, chia phân số}
-> Sử dựng kế thừa: PS2 kế thừa từ PS1
Ví dụ 2: Yêu cầu xây dựng 3 lớp

•Lớp NGƯỜI NGƯỜI


TT: ht, ns, qq
•Lớp SV PT: nhap(), in()

•Lớp GV
SV GV
TT: ht, ns, qq TT: ht, ns, qq
Pt: nhap(), in(), Pt: nhap(), in(),
xeploai() luong()
134
Kế thừa tạo ra mô hình phân cấp:

PS1 NGƯỜI

PS2 SV GV

Ví dụ: một đối tượng SV “là một” loại thuộc lớp NGƯỜI

135
3.3. Xây dựng lớp dẫn xuất
Cú pháp

class <tên lớp dẫn xuất>:[kiểu dẫn xuất]<tên lớp cơ sở>

… // Các thành phần của lớp dẫn xuất

};

136
Trong đó:

•Tên lớp dẫn xuất: Tên lớp được cho kế thừa từ lớp khác

•Tên lớp cơ sở: Là tên lớp đã được định nghĩa trước đó để cho

lớp khác kế thừa. public


protected
•Kiểu dẫn xuất có thể là:
private (ngầm định)

137
• Kiểu dẫn xuất là public: thì các thành phần public của lớp cơ sở chuyển
thành thành viên public của lớp dẫn xuất, các thành viên protected của lớp
cơ sở chuyển thành các thành viên protected của lớp dẫn xuất
• Kiểu dẫn xuất là protected: các thành phần public và protected của lớp cơ sở
chuyển thành các thành viên protected của lớp dẫn xuất
• Kiểu dẫn xuất là private: thì các thành phần public và protected của lớp cơ sở
trở thành các thành viên private của lớp dẫn xuất

138
3.4. Sự kế thừa, lớp cơ sở và lớp dẫn xuất

 Một lớp dẫn xuất ngoài các thành phần của riêng nó, nó còn kế
thừa tất cả các thành phần của các lớp cơ sở có liên quan.

- Lớp dẫn xuất có thể kế thừa các phương thức, thuộc tính của
lớp cơ sở tuy nhiên không thể kế thừa:

-+ Hàm tạo.
- + Hàm hủy.

.
Ví dụ:
+ Định nghĩa lớp Diem có:
Các thuộc tính x,y
Hai hàm tạo.
Phương thức nhap, xuat
+ Xây dựng lớp Hinhtron 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 tính chu vi, diện tích hình tròn.
Phương thức nhap, xuat
#include <conio.h> class HINH_TRON : public DIEM
#include <iostream.h> {
class DIEM private:
{ double r;
private: public:
double x, y; HINH_TRON()
public: {
DIEM() r = 0.0;
{ }
x = y =0.0; HINH_TRON(double x1, double y1,
} double r1): DIEM()
DIEM(double x1, double y1) {
{ r = r1;
x = x1; y = y1; }
} double getR()
void Xuat() {
{ return r;
cout << "\nx= " << x << " y= " << y; }
} };
};
void main()
{
HINH_TRON h(2.5,3.5,8);
clrscr();
cout << "\nHinh tron co
tam: ";
h.Xuat();
cout << "\nCo ban kinh= "
<< h.getR();
getch();
}
Hàm tạo (constructor) trong kế thừa
- Hàm khởi tạo của lớp mẹ không được kế thừa

- Mỗi đối tượng của lớp con có thể coi là một đối tượng của
lớp mẹ.

- Do đó khi gọi hàm khởi tạo của lớp con sẽ kéo theo gọi
hàm khởi tạo của lớp mẹ.

 Thứ tự gọi:

- Hàm khởi tạo lớp mẹ  Hàm khởi tạo lớp con


143
Nếu xây dựng hàm khởi tạo của lớp con: Phải gọi hàm khởi tạo của lớp mẹ
tường minh.
Cú pháp

<hàm khởi tạo dẫn xuất>([tham số]):<hàm khởi tạo cơ sở>([tham


số])

}
Chú ý:
•Hàm khởi tạo lớp cơ sở thực hiện trước.
•Nếu lớp dẫn xuất có nhiều lớp cơ sở thì trình tự thực hiện tuân theo trình tự kế
thừa.
144
Ví dụ:
Lớp Công dân với các thông tin như họ và tên, địa chỉ, số
chứng minh thư.
- Xây dựng lớp Nhân viên kế thừa lớp Công dân có thêm các
thông tin như mã nhân viên, lương cơ bản, phụ cấp.
-Xây dựng các hàm tạo, phương thức nhập và hiển thị thông
tin.

145
146
147
Hàm huỷ trong kế thừa
• Hàm huỷ của lớp cơ sở không được kế thừa.
• Các hàm huỷ được thi hành theo trình tự ngược lại so với
hàm khởi tạo.
• Hàm huỷ của lớp dẫn xuất thi hành trước hàm huỷ của lớp
cơ sở
• Khi một đối tượng của lớp dẫn xuất được giải phóng (bị
hủy), thì các đối tượng thành phần và đối tượng kế thừa từ
lớp cơ sở cũng bị giải phóng theo. Do đó các hàm hủy
tương ứng sẽ được gọi đến.
148
3.5. Đa kế thừa và sự trùng tên trong kế thừa

LỚP D DẪN XUẤT TỪ A VÀ B

LỚP E DẪN XUẤT TỪ C

LỚP F DẪN XUẤT TỪ D

LỚP G DẪN XUẤT TỪ D VÀ E

LỚP H DẪN XUẤT TỪ E

149
3.5. Đa kế thừa và sự trùng tên trong kế thừa
Khái niệm đa kế thừa:
•Là khả năng xây dựng lớp dẫn xuất kế thừa từ nhiều hơn một lớp cơ
sở.
•Đa kế thừa có thể là tính năng rất mạnh nhưng đôi khi gây ra một số
vấn đề.
Xét trường hợp:
Giả sử trong lớp A có thành phần x
Trong lớp B cũng có thành phần x
Xây dựng lớp C kế thừa từ lớp A và B
Theo nguyên lý kế thừa: trong C sẽ có hai thành phần x
150
Vấn đề xảy ra:
Khi truy cập thành phần x trong C thì chương trình
dịch không biết thành phần x đó là của lớp A hay B
 Sự nhập nhằng trong kế thừa.
Để giải quyết:
Ta xác định phạm vi tường minh

151
3.5. Đa kế thừa và sự trùng tên trong kế thừa
Khi kế thừa nhiều mức thì quy tắc đặt tên các thành phần như sau:
- Tên lớp không được trùng lặp
- Tên các thành phần trong một lớp 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 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.
Ví dụ:
C h;// h là đối tượng của lớp C dẫn xuất từ lớp A và lớp B
h.A::x; // thuôc tính x kế thừa từ lớp A
h.B::x;// thuộc tính x kế thừa từ lớp B
152
3.5.1 Các loại kế thừa trong C++
a. Đơn kế thừa (Single Inheritance)
•Đơn kế thừa là gì?
•Đơn kế thừa: nghĩa là một lớp chỉ được kế thừa từ đúng một lớp khác. Hay nói
cách khác, lớp con chỉ có duy nhất một lớp cha.
•Cú pháp:
class subclass_name:: access_mode base_class
{
//body subclass;
};

153
#include <iostream> // Lớp con kế thừa từ lớp cha
using namespace std; class Car : public Vehicle
  {

// Lớp cha };
 
class Vehicle
// main function
{
int main()
public:
{
    Vehicle()     // creating object of sub class will
    {     // invoke the constructor of base classes
        cout << "This is a Vehicle" << endl;     Car obj;
    }     return 0;
}; }

154
b. Đa kế thừa (Multiple Inheritance)
•Định nghĩa
•Đa kế thừa là một tính năng của ngôn ngữ C++. Trong đó một lớp có thể kế thừa
từ nhiều hơn một lớp khác. Nghĩa là một lớp con được kế thừa từ nhiều hơn một
lớp cơ sở.
•Cú pháp khai báo đa kế thừa
•class subclass_name : access_mode base_class1, access_mode base_class2, ....
•{
• //body of subclass
•};

155
#include <iostream> // Lớp cơ sở thứ hai
using namespace std;
class FourWheeler
 // Lớp cơ sở thứ nhất
{
class Vehicle
public:
{
    FourWheeler()
public:
    {
    Vehicle()
    {         cout << "This is a 4
        cout << "This is a Vehicle" << wheeler Vehicle" << endl;
endl;     }
    } };
};  

156
• // Lớp con kế thừa từ 2 lớp cha
• class Car : public Vehicle, public FourWheeler
• {
• };
•  
• // main function
• int main()
• {
•     Car obj;
•     return 0;
• }
157
c. Kế thừa đa cấp (Multilevel Inheritance)
•Định nghĩa
•Kế thừa đa cấp: Trong kiểu thừa kế này, một lớp dẫn xuất được tạo từ một lớp
dẫn xuất khác.

158
#include <iostream> // Lớp con kế thừa từ lớp cha // Lớp con kế thừa từ lớp
using namespace std;
class fourWheeler : public cha thứ 2
  class Car : public
Vehicle
// Lớp cha fourWheeler
class Vehicle { {
{ public: public:
public:     fourWheeler()     car()
    Vehicle()     {     {
    {         cout << "Car has 4
        cout << "Objects with 4
        cout << "This is a Vehicle" << Wheels" << endl;
wheels are vehicles" << endl;
endl;     }
    }     } };
}; };  

159
• // main function
• int main()
• {
•     Car obj;
•     return 0;
• }

160
d. Kế thừa phân cấp (Hierarchical Inheritance)
•Định nghĩa
•Kế thừa phân cấp: Trong kiểu thừa kế này, sẽ có nhiều hơn một lớp con được
kế thừa từ một lớp cha duy nhất.

161
#include <iostream> // Lớp con thứ nhất • int main()
using namespace std;
class Car : public Vehicle • {
  •     Car obj1;
{
// Lớp cha
}; •     Bus obj2;
class Vehicle
{   •     return 0;
public: // Lớp con thứ hai • }
    Vehicle() class Bus : public Vehicle •  
    {
{
        cout << "This is a Vehicle" <<
};
endl;
    }  
}; // main function
162
e. Kế thừa lai (Kế thừa ảo) – Hybrid (Virtual) Inheritance
•Định nghĩa
•Kế thừa lai (Kế thừa ảo): được thực hiện bằng cách kết hợp nhiều hơn một
loại thừa kế. Ví dụ: Kết hợp kế thừa phân cấp và đa kế thừa.

163
#include <iostream> // Lớp cha // Lớp con thứ hai
using namespace std; class Fare class Bus : public Vehicle,
 // Lớp cha { public Fare
class Vehicle public:
{
{     Fare()
};
public:     {
 
    Vehicle()         cout << "Fare of Vehicle\n";
// main function
    {     }
int main()
        cout << "This is a Vehicle" << };
  {
endl;
// Lớp con thứ nhất     Bus obj2;
    }
}; class Car : public Vehicle     return 0;
{}; }

164
• Chú ý: trùng lặp trong đa kế thừa
• Việc kế thừa nhiều lớp cơ sở tạo ra một loại các điểm nhập nhằng. Để phân
biệt giữa các thành viên cùng tên, ta sẽ gọi các thành viên theo cách:
tên đối tượng . Tên lớp : : tên thành phần

165
3.6. lớp cơ sở ảo
Lớp cơ sở xuất hiện nhiều lần trong lớp dẫn xuất
Một điều hiển nhiên là không thể khai báo 2 lần cùng một lớp
trong danh sách của các lớp cơ sở cho một lớp dẫn xuất.
Chẳng hạn ví dụ sau là không cho phép:

Tuy nhiên vẫn có thể có trường hợp cùng 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
một lớp dẫn xuất.

166
Xét ví dụ sau:

167
Từ ví dụ:
Ta thấy: A là cơ sở cho cả 2 lớp cơ sở trực tiếp của D là B và C.
Nói cách khác có 2 lớp cơ sở A cho lớp D. Vì vậy trong câu lệnh:
h.a = 1 ;
thì Chương trình dịch C++ không thể nhận biết được thuộc tính a
thừa kế thông qua B hay thông qua C và nó sẽ đưa ra thông báo
lỗi sau:

Giải pháp cho vấn đề nói trên là khai báo A như một lớp cơ sở kiểu
virtual cho cả B và C
168
3.7. Lớp cơ sở ảo
Khai báo:
class <tên lớp dẫn xuất>: virtual <kiểu dẫn xuất><lớp cơ sở>

169
Các lớp cơ sở ảo (virtual) sẽ được kết hợp để tạo một
lớp cơ sở duy nhất cho bất kỳ lớp nào dẫn xuất từ
chúng.
Trong ví dụ trên, lớp cơ sở A ( A là cơ sở của B và A là
cơ sở của C) sẽ kết hợp lại để trở thành một lớp cơ sở
A duy nhất cho bất kỳ lớp dẫn xuất nào từ B và C.
Như vậy bây giờ D sẽ chỉ có một lớp cơ sở A duy nhất,
do đó phép gán:
h.a = 1 ;
sẽ gán 1 cho thuộc tính a của lớp cơ sở A duy nhất mà
D kế thừa.

170
3.8. Thành viên tĩnh
Khái niệm: Là thành phần dữ liệu của lớp nhưng không
gắn cụ thể với đối tượng nào. Dùng chung cho toàn bộ lớp.
Các đối tượng của lớp đều dùng chung thành phần tĩnh này
Khai báo:
static <kiểu dữ liệu> <tên thành phần>;
class PS{ int ts, ms;
static int count;
public:
PS(int m=0, int n=1){ ts=t; ms=m; count++;}
};
171
Truy xuất:
Theo đối tượng (cách thông thường)
Ví dụ:
PS a;
a.count=0;
Theo lớp
Ví dụ:
PS::count=0

172
Chú ý:
- Tồn tại ngay khi chưa có đối tượng nào
- Phải được khởi tạo trước khi đối tượng phát sinh
- Phải khởi tạo ngoài mọi hàm theo cú pháp:
<kiểu dl> <tên lớp>::<tên thành phần dl> = <giá trị>;
Ví dụ: int PS::count=0;

173
Bài tập
Bài 1.
Xây dựng lớp Nguoi gồm các thông tin sau:
Hoten (char[50]), Ngaysinh (char[12]), Quequan (char[100]), Diemtoan
(int), Diemly (int), Diemhoa (int) và phương thức nhập xuất.
Xây dựng lớp sinhvien kế thừa từ lớp Nguoi có thêm thuộc tính: Lop
(char [30]), Tongdiem (int) và các phương thức nhập dữ liệu từ bàn
phím và xuất dữ liệu ra màn hình.
Yêu cầu : Xây dựng các hàm tạo, hàm hủy phương thức nhập và hiển thị
thông tin.

174
Bài tập
Bài 2. ( sử dụng đa kế thừa)
- Xây dựng lớp Nguoi gồm các thông tin sau:
Hoten (char[50]), Ngaysinh (char[12]), Quequan (char[100]) và phương
thức nhập, xuất dữ liệu.
- Xây dựng lớp diem gồm: Thuộc tính: Diemtoan (int), Diemly (int),
Diemhoa (int) và phương thức nhập xuất.
- Xây dựng lớp sinhvien kế thừa từ 2 lớp trên có thêm thuộc tính: Lop (char
[30]), Tongdiem (int) và các phương thức nhập, xuất từ bàn phím.
Yêu cầu: Xây dựng các hàm tạo, hàm hủy, phương thức nhập và hiển thị
thông tin

175
Bài 3: Xây dựng lớp Người, Môn học, Giáo viên
Lớp NGUOI gồm các thuộc tính họ tên, năm sinh
- Hai hàm tạo, nhập,phương thức in và hàm huỷ
Lớp MON_HOC gồm các thuộc tính tên môn học, số tiết
- Hai hàm tạo, nhâp, 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 bộ môn công tác, môn học giảng dạy.
- Hai hàm tạo, nhâp, phương thức in() và hàm huỷ

176
CHƯƠNG 4

177
Nội dung học buổi 7

4.1. Phương thức tĩnh


4.2. Đa hình

178
4.1. Phương thức tĩnh
Các phương thức ta đã xây dựng từ trước đến nay đều là phương thức tĩnh.
Xét ví dụ: class A cout << "\n Lop B " ;
{ }
public: };
void xuat() class C:public B
{
{
cout << "\n Lop A " ;
} public:
}; void xuat()
class B:public A {
{ cout << "\n Lop C " ;
public: }
void xuat() };
{

179
Lớp C có 2 lớp cơ sở là A , B và C kế thừa các phương thức của A và
B.
Do đó một đối tượng của C sẽ có tới 3 phương thức xuat.
Ví dụ:
C h; // h là đối tượng kiểu C
h.xuat() ; // Gọi tới phương thức h.C::xuat()
h.B::xuat() ; // Gọi tới phương thức h.B::xuat()
h.A::xuat(); // Gọi tới phương thức h.A::xuat()
Các lời gọi phương thứ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ương thức cần gọi.

180
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 la các 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
181
Quy tắc gọi hàm ảo
• Quy tắc gọi hàm tĩnh:
• Nếu lời gọi xuất phát từ một đối tượng của lớp nào thì hàm thành phần
của 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ì hàm thành phần của
lớp đó sẽ được gọi bất kể con trỏ chứa địa chỉ của đối tượng nào
• Quy tắc gọi hàm ảo: hàm ảo chỉ khác hàm tĩnh khi gọi từ một con trỏ, lời
gọi tới hàm ảo từ một con trỏ chưa biết rõ hàm nào sẽ được gọi. Con trỏ
đang trỏ tới đối tượng của lớp nào thì hàm của lớp đó sẽ được gọi

182
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 tuợng của lớp dẫn xuất.
p=&a;
q=&b;
r=&c;
Xét các lời gọi phương thức từ các con trỏ p, q,r:
p->xuat();
q->xuat();
r->xuat();
và hãy cho biết phương thức nào (trong các phương thức A::xuat,
B::xuat và C::xuat) được gọi?
183
Cả 3 câu lệnh trên đều gọi tới phương thức A::xuat(), vì các con
trỏ p, q và r đều có kiểu A.
Kết luận: Đối với phương thức tĩnh
-Lời gọi xuất phát từ đối tượng của lớp nào, thì phương thức
lớp đó được gọi.
-Lời gọi xuất phát từ con trỏ của lớp nào, thì phương thức lớp
đó được gọi bất kể con trỏ chứa địa chỉ của đối tượng nào.
- Quy tắc gọi hàm ảo: hàm ảo chỉ khác hàm tĩnh khi gọi từ một con trỏ, lời gọi tới
hàm ảo từ một con trỏ chưa biết rõ hàm nào sẽ được gọi. Con trỏ đang trỏ tới đối
tượng của lớp nào thì hàm của lớp đó sẽ được gọi

184
Xét bài toán
- Xây dựng lớp TS. Mỗi thí sinh đưa vào ba thuộc tính: Họ
tên, số báo danh và tổng điểm. Chương trình gồm ba chức
năng: Nhập dữ liệu thí sinh, in dữ liệu thí sinh ra máy in và
xem - in (in sinh viên có tổng điểm >15).
- Xây dựng lớp TS2 dẫn xuất từ lớp TS. Trong lớp TS2 đưa
thêm thuộc tính DC (địa chỉ) và các phương thức nhập, in
(khi in chỉ in những người có tổng điểm >15)

185
186
Ta thấy: Khi in ra thí sinh có tổng điểm >15 nhưng
không có trường Địa chỉ vì Lớp thí sinh2 không định
nghĩa phương thức Xem thông tin mà sẽ dùng
phương thức xemthongtin của lớp Thisinh vì vậy? Bài
toán chưa được giải quyết.
-> Đa hình

187
4.2. Polymorphism (Đa hình)
• Sự kế thừa trong LTHĐT cho phép có sự tương ứng giữa lớp cơ sở
và các lớp dẫn xuất trong sơ đồ kế thừa.
• Một con trỏ có kiểu lớp cơ sở luôn có thể trỏ đến địa chỉ của một
đối tượng của lớp dẫn xuất.
Tuy nhiên, khi thực hiện lời gọi một phương thức của lớp, trình biên
dịch sẽ quan tâm đến kiểu của con trỏ chứ không phải đối tượng
mà con trỏ đang trỏ tới:
Phương thức của lớp mà con trỏ có kiểu được gọi chứ không phải
phương thức của đối tượng mà con trỏ đang trỏ tới được gọi.

188
Để giải quyết vấn đề này, LTHĐT đưa ra một khái
niệm:
Phương thức của lớp cha khi thực hiện sẽ được thay thế
bằng một phương thức của lớp con thì phương thức này
gọi là có tính đa hình.
Tính đa hình giúp cho việc lập trình đơn giản và dễ mở
rộng. Để cài đặt phương thức có tính đa hình ta dùng
phương thức ảo và phương thức thuần ảo.
189
Phương thức ảo
Những phương thức được khai báo từ khóa virtual ở lớp cha. Khi đó lớp con kế
thừa lại từ nó cũng cài đặt phương thức “Trùng tên” để cho phép có thể nạp chồng
lại được.

Tác dụng từ khóa virtual:


+ Cho phép các lớp con nạp chồng lại được phương thức có trùng tên của lớp cha
(tức là ta new ra đối tượng con nào thì khi trỏ tới phương thức trùng tên, nó sẽ hiểu
là gọi vào phương thức của đối tượng con đó)
+ Nếu lớp cha không cài đặt từ khóa virtual thì new ra bất kỳ lớp con nó luôn luôn
vẫn gọi về lớp cha.

190
Ví dụ 1 Mặc dù New lớp C nhưng vẫn gọi
phương thức lớp A vì con trỏ P khai
báo ở lớp A
-> Xây dựng Void nhap và Void xuat
theo phương thức ảo

191
Ví dụ 11

192
Phương thức thuần ảo
Mục đích:
Tránh lãng phí bộ nhớ
Cung cấp một phương thức thống nhất làm giao diện chung.
Khai báo lớp cha:
virtual <kiểu dữ liệu> <tên phương thức>([tsố])=0;
Khi sử dụng phương thức thuần ảo: Lớp cha không có thông tin nào để tính
toán thì ta sử dụng thuần ảo để cho các lớp con đảm nhận nhiệm vụ tính
toán đó.
Lưu ý: Khi lớp cha sử dụng phương thức thuần ảo thì bắt buộc “tất cả” mọi
lớp con đều phải cài đặt cho nó, nếu có lớp con nào không cài đặt thì khi new
lớp con đó chương trình sẽ bị lỗi.
193
Ví dụ 2:
class A class C:public A
{ {
public: public:
virtual void nhap() void nhap()
{ {
cout<<"\nNhap lop A"; cout<<"\nNhap lop C";
} }
virtual void xuat() void xuat()
{ {
cout << "\n Lop A " ; cout << "\n Lop C " ;
} }
}; };
class B:public A main()
{ {
public: A *p =new C;
void nhap() p->nhap() ;
{ p->xuat() ;
cout<<"\nNhap lop B"; }
}
void xuat()
{
cout << "\n Lop B " ; 194
Phương thức ảo khác với thuần ảo ở chỗ nào?
• Phương thức ảo được sử dụng khi lớp cha có thông tin để
thực hiện hành động gì đó.
• Phương thức thuần ảo được sử dụng khi lớp cha không có
thông tin nhưng lớp con lại có => việc cài đặt sẽ do lớp con
làm.

195
Bài tập
• Bài 1:
• A. xây dựng lớp Tong2So gồm có hàm tạo và hàm tinhtong để tính tổng 2 số
nguyên a, b
• B. xây dựng lớp tongbp, tonglp kế thừa từ lớp tong2so. Hai lớp này đều có
hàm tinhtong để tính tổng bình phương và tổng lập phương của 2 số a, b
• C. chương trình chính khai báo con trỏ của lớp tong2so và đối tượng của lớp
tongbp, tonglp, Cho con trỏ của lớp tong2so trỏ đến địa chỉ của lớp tongbp,
tonglp để gọi hàm tinhtong của các lớp tương ứng

196
• Bài 2: xây dựng lớp media mô tả các đối tượng phương tiện truyền thông lớp gồm:
• Thành phần dữ liệu tên gọi, giá bán
• Hàm nhập dữ liệu
• Hàm hiển thị dữ liệu
B xây dựng lớp book mô tả các đối tượng sách. Lớp được kế thừa từ lơp media
và bổ sung thêm:
thành phần dữ liệu mô tả số trang, tác giả
- Hàm nhập dữ liệu
- Hàm hiển thị dữ liệu
c. Xây dựng lớp video mô tả các đối tượng bằng video, lớp kế thừa từ lớp media
và bổ sung thêm:

197
• Hàm thành phần dữ liệu thời gian chạy
• Hàm nhập dữ liệu
• Hàm hiển thị dữ liệu
• D.

198
CHƯƠNG 4

199
Nội dung học buổi 8

4.3. Lớp cơ sở trừu tượng


4.4. Giao diện (interface)
Ôn tập
Kiểm tra

200
Lớp cơ sở trừu tượng (abstract class)
Lớp cơ sở trừu tượng là một lớp chỉ được dùng làm cơ sở cho các
lớp khác.
Không hề có đối tượng nào của một lớp trừu tượng được tạo ra cả,
bởi vì nó chỉ được dùng để định nghĩa một số khái niệm tổng quát
chung cho các lớp khác.
Ví dụ: Ta có lớp Convat nó sẽ dùng làm cơ sở để xây dựng các lớp
con vật cụ thể như: Conmeo, concho…
- Thuật ngữ “Trừu tượng” đặc biệt áp dụng cho các lớp có chứa
phương thức thuần ảo.

201
202
4.4. Giao diện (Interface)
• Giao diện (Interface): là một chức năng mà ta có thể thêm và bất kì class
nào. Chức năng ở đây không đồng nghĩa với phương thức (hoặc hàm).
• Interface có thể bao gồm nhiều hàm/phương thức và tất cả chúng cùng
phục vụ cho một chức năng.
Như vậy, Interface được dùng để mô tả một "bản thiết kế" cho một chức
năng của class.
• Interface không phải là lớp. Các lớp dẫn xuất từ 1 Interface đều phải
định nghĩa đầy đủ các phương thức và thuộc tính kế thừa từ
Interface.
• Mục đích của một Interface là để định nghĩa những khả năng mà chúng
ta muốn có trong một lớp.

203
interface class A
{
...
}
==> lớp A là một giao diện (interface);
•Không thể tạo ra một thực thể của A;
•A khai báo những phương thức mà không hiện thực (tức là
không có thân của phương thức);
•Không thể hiện thực 1 phương thức trong A, A không chứa
thuộc tính (biến thành viên)
204
Ví dụ:
Một interface tên là IShape chỉ có một phương thức là
calarea() dùng để tính toán diện tích.
Đối tượng Circle và đối tượng Rectangle đều có thể dùng
được giao diện này dù cách thức thực thi là khác nhau.
Tuy vậy một đối tượng cần tương tác thông qua giao diện
IShape đều chỉ cần gọi phương thức calarea() bất kể đó là
Circle hay Rectangle

205
- Giả sử có 2 lớp: Lớp Máy bay & Lớp Chim. Ta thấy Máy bay có chức năng bay.
Chim cũng có khả năng bay.
- Ví dụ 1: Tạo Interface: Bay (IBay) cho lớp May bay & Lớp Chim thừa kế.

206
Đề kiểm tra thực hành
Nhân viên trong một cơ quan được lĩnh lương theo các dạng khác nhau:
Người lao động hưởng lương từ ngân sách Nhà nước gọi là cán bộ,
công chức (dạng biên chế).
Người lao động lĩnh lương từ ngân sách gọi là người làm hợp đồng.
Như vậy hệ thống có hai đối tượng:
biên chế và hợp đồng.          
Hai loại đối tượng này có đặc tính chung là viên chức làm việc cho cơ quan.
Từ đây có thể tạo nên lớp cơ sở để quản lý một viên chức (lớp Nguoi) bao
gồm mã số, họ tên, lương.          
- Hai lớp kế thừa từ lớp cơ sở trên:
+ Lớp Bienche gồm các thuộc tính: hệ số lương, tiền phụ cấp chức vụ.
+ Lớp Hopdong gồm các thuộc tính: tiền công lao động, số ngày làm việc
trong tháng, hệ số vượt giờ.
Hãy thiết kế các lớp trên và viết chương trình minh họa.

207
CHƯƠNG 4

208
Nội dung học buổi 9

4.5. Khuôn mẫu (Template)


4.5.1. Khuôn mẫu hàm
4.5.2. Khuôn mẫu lớp
4.6. Ôn tập + trả điểm

209
Đặt vấn đề
Ví dụ 1: xây dựng hàm tìm max của hai số
thực
- Xây dựng hàm tính max của ba số thực
- Xây dựng hàm tính max của n số thực

Giải quyết:
Nạp chồng hàm max
Vấn đề được giải quyết, nhưng phải viết n
hàm

 Khuôn mẫu (Template)


4.5. Khuôn mẫu (Template)
Template là gì.?
- Template (Khuôn hình - Mẫu ) đặc trưng cho việc tổng
quát hóa việc xử lý với các kiểu dữ liệu khác nhau.
- template là một từ khóa trong C++, nó biểu diễn cho
một kiểu dữ liệu trừu tượng có thể là int, float, class….

211
• Tại sao lại sử dụng template ? Thay vì viết overloading từng phương thức
cho các kiểu dữ liệu khác nhau thì ta chỉ cần viết một phương thức template
cho tất cả.
• Có 2 loại template cơ bản:
• Function template: là một khuôn mẫu hàm, cho phép định nghĩa các hàm
tổng quát thao tác cho nhiều kiểu dữ liệu.
• Class template: là một khuôn mẫu lớp, cho phép định nghĩa các lớp tổng
quát cho nhiều kiểu dữ liệu.

212
Ví dụ
• void swap(int &a, int &b) { • template<typename T>
•     int temp = a; • void swap(T &a, T &b) {
•     a = b; •     T temp = a;
•     b = temp; •     a = b;
• } •     b = temp;
•   • }
• void swap(float &a, float &b) { •  
•     float temp = a;
•     a = b;
•     b = temp;
• }
213
4.5.1. Khuôn hình hàm
Ví dụ: xây dựng hàm tìm max của hai số bất kỳ

Giải quyết:

int max(int a, int b){ float max(float a, float


b){
if(a>b) return a;
if(a>b) return a;
else return b;}
else return b;}
4.5.1. Khuôn hình hàm
Khái niệm
Khuôn hình hàm cho phép sử dụng cùng một tên duy nhất
để thực hiện các công việc khác nhau.
4.5.1. Khuôn hình hàm
4.5.1. Khuôn hình hàm
Gọi hàm từ khuôn hình hàm
tên hàm<kieudl>(đối số)
Tên hàm trùng tên khuôn hình hàm
Ví dụ:
Với khuôn hình hàm max với 2 số kiểu nguyên
int a,b;
Max<int>(a,b) ;
Khi đó chương trình dịch sẽ xác định:
-Kiểu của a,b là int nên kiểu của T cũng sẽ là int
-Phát sinh một hàm cụ thể từ khuôn hình hàm max
Ví dụ 1: tìm số lớn nhất giữa 2 số cùng kiểu

218
Ví dụ 2: tìm số lớn nhất giữa 2 số khác kiểu

219
Overload (nạp chồng)
Các hàm được viết dưới dạng template đều có thể được nạp chồng như những
hàm bình thường khác.

220
4.5.2. Khuôn hình lớp
Địnhnghĩa các Class Template (Khuôn hình lớp) một lần rồi sau đó có
thể áp dụng chúng với các kiểu dữ liệu khác nhau để được các lớp thể
hiện khác nhau.
- Class : Nhóm các dữ liệu khác kiểu vào với nhau thành 1 lớp; bao gói
dữ liệu và việc xử lý dữ liệu đó vào cùng một chỗ. Tăng tính bảo mật cho
dữ liệu cũng như abstraction (trừu tượng hóa) dữ liệu với người dùng.
- Template : Gom các xử lý với nhiều kiểu dữ liệu khác nhau về cùng một
chỗ để tránh việc viết lại code và tổng quát hóa quá trình xử lý dữ liệu.
-->> class template.

221
Khai báo khuôn hình lớp

222
4.5.2. Khuôn hình lớp
Ví dụ:

Định nghĩa các hàm thành phần của khuôn hình lớp, phân biệt hai trường
hợp:
- Khi hàm thành phần được định nghĩa bên trong lớp thì không có gì
thay đổi.
-Khi hàm thành phần được định nghĩa bên ngoài lớp, khi đó cần phải nhắc lại cho
chương trình biết các tham số kiểu của khuôn hình lớp.
Ví dụ: phải nhắc lại template <class kieuso> trước định nghĩa hàm.
224
Sử dụng khuôn hình lớp
Ví dụ về khuôn hình lớp- định nghĩa trong lớp

226
Ví dụ về khuôn hình lớp- định nghĩa trong lớp

227
Vậy khi nào thì ta nên sử dụng template :
- Khi ta muốn xây dựng một lớp hay một hàm xử lý những
công việc chung cho nhiều kiểu khác nhau.
- Mục tiêu của việc tổng quát hóa lập trình là khiến người sử
dụng lớp hay hàm đó không phải bận tâm về các kiểu khác
nhau. Khi đó công việc "ẩn" đi các xử lý với các kiểu khác
nhau được đẩy cho người viết hàm hay lớp tổng quát đó.
- Công việc sử dụng lại mã sẽ hết sức đơn giản.

228
Bài tập
• Bài 1: xây dựng khuôn hình hàm min để tìm giá trị nhỏ nhất của 2 số cùng
kiểu
• Bài 2: Xây dựng chương trình gồm các khuôn hình hàm sau:
• Khuôn hình 1: tìm giá trị nhỏ nhất trong hai giá trị cùng kiểu
• Khuôn hình 2: tìm số nhỏ nhất trong ba giá trị cùng kiểu
• Khuôn hình 3: tìm số nhỏ nhất trong một mảng
Bài 3: nhập vào mảng có n phần tử là số, sắp xếp mảng theo chiều tăng dần và
in mảng đã sắp ra màn hình
(yêu cầu: xây dựng khuon tình lớp để thực hiện công việc )

229
Bài tập về khuôn mẫu
• Xây dựng khuôn hình hàm HoanVi() để hoán vị hai số truyền vào.
• Xây dựng khuôn hình hàm SapXep() dùng để sắp xếp một mảng
theo thứ tự tăng trong đó có sử dụng khuôn hình hàm hoanVi().
• Xây dựng khuôn hình hàm Nhap() để nhập một mảng từ bàn phím.
• Xây dựng khuôn hình hàm Xuat() để xuất một mảng ra màn hình.
Sử dụng các khuôn hình đã xây dựng để viết một chương trình nhập,
sắp xếp và xuất ba mảng:một mảng nguyên, một mảng thực và một
mảng ký tự.

230

You might also like