1. NHP, Khoa CNTT, Trường ĐHHHVN
Chương 2. Đối tượng và lớp
2.1. Định nghĩa đối tượng, lớp.
2.2. Khai báo lớp, đối tượng.
2.3. Cấu tử và hủy tử.
2.4. Thành phần tĩnh, hàm bạn, lớp bạn.
2.5. Định nghĩa chồng toán tử.
2. NHP, Khoa CNTT, Trường ĐHHHVN
2.1. Định nghĩa đối tượng, lớp.
Đối tượng (object): là một thực thể tồn tại trong hệ thống. Mỗi
đối tượng xác định bằng 3 yếu tố:
định danh đối tượng: xác định duy nhất đt trong hệ thống, phân biệt các
đt với nhau
trạng thái của đt: là các thuộc tính mô tả đt
hoạt động của đt: là những hành động mà đt có thể thực hiện được.
3. NHP, Khoa CNTT, Trường ĐHHHVN
2.1. Định nghĩa đối tượng, lớp.
Ví dụ: Bài toán quản lý nhân viên, mỗi nhân viên là một đối tượng.
– Nhân viên tên là Huy, tuổi 28, hệ số lương 3.00; … là một đối tượng,
Kết quả của việc trừu tượng hóa các đối tượng của thế giới thực
thành các đối tượng lập trình là sự kết hợp giữa dữ liệu (thuộc
tính) và các hàm (phương thức).
4. NHP, Khoa CNTT, Trường ĐHHHVN
2.1. Định nghĩa đối tượng, lớp
Lớp (class) là một kiểu dữ liệu mới được dùng để định nghĩa
các đối tượng.
Một lớp có vai trò như một kế hoạch hay một bản mẫu.
Việc viết hay tạo ra một lớp mới không sinh ra bất cứ một đối
tượng nào trong chương trình.
5. NHP, Khoa CNTT, Trường ĐHHHVN
2.2. Khai báo lớp, đối tượng
Khai báo lớp
class tên_lớp [: <kiểu thừa kế> lớp_cha]{
private: // Khai báo các thành phần dữ liệu (thuộc tính) riêng
// Khai báo các phương thức (hàm) riêng
protected: // Khai báo các thành phần dữ liệu được bảo vệ
// Khai báo các phương thức được bảo vệ
public: // Khai báo các thành phần dữ liệu chung
// Khai báo các phương thức chung
};
7. NHP, Khoa CNTT, Trường ĐHHHVN
Khai báo đối tượng
Giống như khai báo biến thông thường
Tên_lớp tên_đối_tượng;
Ví dụ:
SV a;
SV b[10];
SV *p;
…
Truy cập:
tên_đối_tượng.tên_pt/tên_tp
tên_đối_tượng->tên_pt/tên_tp //với con trỏ
a.ten
a.nhap()
a.tong()
p->xuat()
p->ns
…
8. NHP, Khoa CNTT, Trường ĐHHHVN
Các thành phần trong lớp
Các từ khóa private, protected, public quy định phạm vi sử dụng
của các tp dữ liệu hoặc pt.
từ khóa trong lớp ngoài lớp bạn bè thừa kế
pri x x
pro x x x
pub x x x x
9. NHP, Khoa CNTT, Trường ĐHHHVN
Con trỏ this
Tất cả các phương thức hoặc tp dữ liệu phải được gọi thông
qua đối tượng nào đó,
Con trỏ this tham chiếu đến đối tượng đang gọi hàm thành
phần,
Con trỏ this trong C++ là một từ khóa đề cập đến thể hiện hiện
tại của lớp,
12. NHP, Khoa CNTT, Trường ĐHHHVN
2.3. Cấu tử và hủy tử.
Cấu tử (constructor): hàm thành phần có nhiệm vụ khởi tạo giá
trị ban đầu cho dữ liệu của đối tượng.
Đặc điểm:
– trùng tên với tên lớp
– có nhãn public
– không có kiểu trả về
– có hoặc không có tham số (hàm tạo ngầm định)
– tự động được gọi khi đt được khai báo
– nếu không xd tường minh thì chương trình tự sinh ra một hàm tạo
không tham số, không nội dung
13. NHP, Khoa CNTT, Trường ĐHHHVN
Cấu tử
class MyClass{
const int ci;
int x;
public:
MyClass():ci(0),x(0){}
};
hoặc MyClass(): ci(0){x=0;}
14. NHP, Khoa CNTT, Trường ĐHHHVN
Cấu tử
class PS{
int ts, ms;
public:
PS():ts(1), ms(2){}
PS(int t, int m=9){ts=t; ms=m;}
};
PS a; // dùng hàm mặc định
PS b(2); // dùng hàm có tham số
PS x[10], y[5]={{3}, {5, 6}, 7, PS(2, 3)};
15. NHP, Khoa CNTT, Trường ĐHHHVN
Cấu tử sao chép (Copy Constructor)
Nhiệm vụ của hàm thiết lập sao chép là tạo ra một đối tượng giống hệt
một đối t
ượng đã có.
Tạo đối tượng mới và sao chép nội dung của đối tượng cũ sang đối
tượng mới.
ten_lop (const ten_lop &obj)
{
// phần thân của copy constructor
}
16. NHP, Khoa CNTT, Trường ĐHHHVN
Huỷ tử (Destructor)
Là phương thức dùng để huỷ bỏ đối tượng
Chỉ có duy nhất một hàm hủy trong một lớp.
Có tên trùng với tên lớp, có dấu ~ phía trước.
Không có tham số.
Không có kiểu trả về.
Được gọi tự động khi đối tượng đi ra khỏi phạm vi:
– Kết thúc hàm
– Kết thúc chương trình
– Kết thúc một block
– Toán tử delete được gọi
18. NHP, Khoa CNTT, Trường ĐHHHVN
2.4. Thành phần tĩnh, hàm bạn, lớp bạn
Thành phần tĩnh:
– Thuộc tính tĩnh
– Phương thức tĩnh
Hàm bạn, lớp bạn
19. NHP, Khoa CNTT, Trường ĐHHHVN
2.4. Thành phần tĩnh, ...
Thuộc tính tĩnh (static attribute) là những thuộc tính thuộc về bản
thân lớp chứ không thuộc về bất cứ thực thể nào của nó.
1 thuộc tính tĩnh sẽ giống như 1 biến toàn thể, nghĩa là có thể
được truy cập từ bất cứ đâu trong đoạn mã
Khai báo: thêm từ khoá static vào đầu dòng khai báo thuộc tính
class Ten_Lop{
static int x;
int y;
public:
Ten_Lop(){...}
};
Khởi tạo giá trị thuộc tính static ở bên ngoài lớp
int Ten_Lop::x = 5;
20. NHP, Khoa CNTT, Trường ĐHHHVN
2.4. Thành phần tĩnh, ...
Phương thức tĩnh (static method) là những phương thức thuộc về
bản thân lớp chứ không thuộc về bất cứ thực thể nào của nó.
Có thể coi là những hàm bình thường được xếp vào trong khai
báo lớp nhưng lại không tác động gì đến các thuộc tính của lớp.
class TenLop{
public:
TenLop();
static void phuongThuc();
};
void TenLop::phuongThuc(){
cout << "Xin chao !" << endl;
}
int main(){
TenLop::phuongThuc();
TenLop a;
a.phuongThuc(); //sai
return 0;
}
21. NHP, Khoa CNTT, Trường ĐHHHVN
2.4. Thành phần tĩnh – ví dụ
#include <iostream>
using namespace std;
class PS{
public:
PS(int t, int m);
~PS();
static int soThucThe();
private:
int ts, ms;
static int soLuong;
};
int PS::soLuong = 0;
PS::PS(int t, int m) : ts(t), ms(m){
soLuong++;
}
PS::~PS(){
soLuong--;
}
int PS::soThucThe(){
return soLuong; //Tra ve gia trị cua bien dem
}
int main(){
PS x(1, 2);
PS y(3, 5);
cout << "Da tao ra " << PS::soThucThe() << " phan so." << endl;
return 0;
}
22. NHP, Khoa CNTT, Trường ĐHHHVN
2.4. ...hàm bạn, lớp bạn
Trong OOP, khái niệm quan hệ bạn ( friend ) nghĩa là trao quyền truy cập hoàn toàn tới tất
cả các thành viên của 1 lớp cho 1 hàm.
Khi khai báo 1 hàm bạn đồng nghĩa với việc chúng ta hủy hoàn toàn tính đóng gói của lớp
bởi lẽ 1 đoạn mã bên ngoài lớp có thể dễ dàng thay đổi nội dung của lớp.
Hàm tự do là bạn của lớp
Hàm của lớp A là bạn của lớp B
Lớp A là bạn của lớp B
23. NHP, Khoa CNTT, Trường ĐHHHVN
2.4. ...hàm bạn, lớp bạn
Khai báo
class A{
//nội dung của A
friend void fct();
};
void fct(){
//nội dung hàm fct
}
class B;
class A{
//nội dung của A
friend class B;
};
class B{
//nội dung của B
};
24. NHP, Khoa CNTT, Trường ĐHHHVN
2.4. ...ví dụ
Xây dựng lớp SV.
Xây dựng hàm sắp xếp danh sách sv theo tên.
25. NHP, Khoa CNTT, Trường ĐHHHVN
2.4. ...ví dụ
Cách 1: dùng hàm bạn
#include <iostream>
using namespace std;
class SV{
string ten;
int ma;
double d1, d2, d3;
public:
SV();
void nhap();
void in();
friend void sxep(SV a[], int spt);
};
void sxep(SV a[], int spt){
for(int i=0; i<spt-1; i++)
for(int j=i+1; j<spt; j++)
if(a[i].ten > a[j].ten)
{
SV tg=a[i];
a[i]=a[j];
a[j]=tg;
}
}
int main(){
SV a[100];
int spt;
//...
sxep(a, n);
//...
}
26. NHP, Khoa CNTT, Trường ĐHHHVN
2.4. ...ví dụ
Cách 2: dùng lớp bạn
#include <iostream>
using namespace std;
class DSSV;
class SV{
string ten;
int ma;
double d1, d2, d3;
public:
SV();
void nhap();
void in();
friend class DSSV;
};
class DSSV{
int spt;
SV *a;
public:
void nhap();
void in();
void sxep();
};
void DSSV::sxep(){
for(int i=0; i<spt-1; i++)
for(int j=i+1; j<spt; j++)
if(a[i].ten > a[j].ten)
{
SV tg=a[i];
a[i]=a[j];
a[j]=tg;
}
}
int main(){
DSSV ds;
ds.nhap();
ds.sxep();
ds.in();
return 0;
}
27. NHP, Khoa CNTT, Trường ĐHHHVN
2.5. Chồng toán tử (operator overloading)
Khái niệm chồng (quá tải) toán tử
Ưu nhược điểm của chồng toán tử
Cách quá tải hàm toán tử
Khả năng và giới hạn của chồng toán tử
Ví dụ một số toán tử cơ bản
28. NHP, Khoa CNTT, Trường ĐHHHVN
Khái niệm chồng toán tử
Với biểu thức a+b, ký hiệu + tuỳ theo kiểu của a và b có thể biểu
thị:
– phép cộng hai số nguyên,
– phép cộng hai số thực độ chính xác đơn (float),
– phép cộng hai số thực chính xác đôi (double),
– phép cộng một số nguyên vào một con trỏ,
– Phép cộng 2 ma trận,
– Phép cộng 2 phân số,
– …
29. NHP, Khoa CNTT, Trường ĐHHHVN
Khái niệm chồng toán tử
Ví dụ: Xây dựng lớp PS có:
– Thuộc tính: ts, ms
– Phương thức: khởi tạo, nhập, xuất
– Hàm bạn: cong(PS a, PS b) - cộng 2 phân số
– hoặc phương thức cong(…) – cộng 2 phân số
30. NHP, Khoa CNTT, Trường ĐHHHVN
Khái niệm chồng toán tử
class PS{
int ts, ms;
public:
PS(int t=1, int m=2){
ts=t;
ms=m;
}
void nhap();
void xuat();
friend PS cong(PS a, PS b);
};
PS cong(PS a, PS b)
{
PS c;
c.ts=a.ts*b.ms+a.ms*b.ts;
c.ms=a.ms*b.ms;
return c;
}
…
PS x , y(2, 3) , z(1, 5);
x = cong(y, z);
? x=y+z;
31. NHP, Khoa CNTT, Trường ĐHHHVN
Ví dụ-lớp PS
class PS{
int ts, ms;
public:
PS(int t=1, int m=2){
ts=t;
ms=m;
}
void nhap();
void xuat();
friend PS operator+(PS a, PS b);
};
PS operator+(PS a, PS b)
{
PS c;
c.ts=a.ts*b.ms+a.ms*b.ts;
c.ms=a.ms*b.ms;
return c;
}
…
PS x, y(2, 3), z(1, 5);
x=y+z;//kết quả 13/15
32. NHP, Khoa CNTT, Trường ĐHHHVN
Khái niệm chồng toán tử
Xét biểu thức a+b
+ là toán tử
a, b là toán hạng
Một số toán tử trong C++
– các toán tử toán học: +, -, *, /, %
– các toán tử quan hệ: >, <, >=, <=, ==, !=
– toán tử logic: !, &&, ||
– toán tử >>, <<
– toán tử -, ++, --
– toán tử new, delete, sizeof, ?:
– .v.v.
34. NHP, Khoa CNTT, Trường ĐHHHVN
Khái niệm chồng toán tử
Các hàm được
định nghĩa
chồng
Các toán tử
cũng là các hàm
(hàm toán tử)
Chồng toán tử là gì?
Các toán tử
cũng được định
nghĩa chồng
Định nghĩa lại các
toán tử sao cho
chúng có thể thực
hiện với các toán
hạng khác nhau.
35. NHP, Khoa CNTT, Trường ĐHHHVN
Ưu nhược điểm của chồng toán tử
Làm cho các chương trình dễ viết hơn, cũng dễ hiểu hơn,
dễ bảo trì
Có thể thay thế toán tử chồng bằng một hàm
Chồng toán tử là cách duy nhất gọi một hàm KHÁC cách
gọi thông thường
– x=cong(y, z);
– x=y+z;
36. NHP, Khoa CNTT, Trường ĐHHHVN
Ví dụ: Xây dựng lớp PS
Cách 1: có hàm cong(PS a, PS b) để cộng phân số a
và phân số b
Cách 2: toán tử + để cộng phân số a và phân số b
37. NHP, Khoa CNTT, Trường ĐHHHVN
Quy tắc xây dựng hàm toán tử
Hàm toán tử có thể được quá tải là phương thức của lớp hoặc hàm bạn:
– Nếu là phương thức thì số tham số của hàm bằng số ngôi của toán tử -1
– Nếu là hàm bạn thì số tham số của hàm bằng số ngôi
Một trong số các toán hạng phải là đối tượng
Khai báo: kiểu_hàm operator op(các tham số)
– op: là ký hiệu toán tử tương ứng
– operator: là từ khoá để khai báo hàm toán tử
– PS operator+(PS a, PS b);
38. NHP, Khoa CNTT, Trường ĐHHHVN
Cách xây dựng
kiểu_hàm operator op (các tham số)
{
//nội dung hàm toán tử
}
op: toán tử cần quá tải (+, -, *, /, …)
Tên hàm Dùng để
operator+ định nghĩa phép +
operator* định nghĩa phép nhân *
operator/ định nghĩa phép chia /
operator+= định nghĩa phép tự cộng +=
operator!= định nghĩa phép so sánh khác nhau
39. NHP, Khoa CNTT, Trường ĐHHHVN
Cách xây dựng
class PS{
int ts, ms;
public:
PS(int t=1, int m=2){
ts=t;
ms=m;
}
void nhap();
void xuat();
friend PS operator+(PS a, PS b);
};
PS operator+(PS a, PS b)
{
PS c;
c.ts=a.ts*b.ms + a.ms*b.ts;
c.ms=a.ms*b.ms;
return c;
}
…
PS x, y(2, 3), z(1, 5);
x=y+z;//kết quả 13/15
Nguyên mẫu
Định nghĩa hàm
Gọi hàm
x=operator+(y, z);
40. NHP, Khoa CNTT, Trường ĐHHHVN
Cách xây dựng
class PS{
int ts, ms;
public:
PS(int t=1, int m=2){
ts=t;
ms=m;
}
void nhap();
void xuat();
PS operator+(PS b);
};
PS PS::operator+(PS b)
{
PS c;
c.ts = this->ts * b.ms + this-> ms * b.ts;
c.ms = this->ms * b.ms;
return c;
}
…
PS x, y(2, 3), z(1, 5);
x=y+z;//kết quả 13/15
Nguyên mẫu
Định nghĩa hàm
Gọi hàm
x=y.operator+(z);
43. NHP, Khoa CNTT, Trường ĐHHHVN
Quy tắc xây dựng
Dạng phương thức: khuyết tham số thứ nhất (toán hạng thứ
nhất
Toán hạng bên trái nhất của toán tử được overload phải là 1
đối tượng của kiểu class mà toán hạng khai báo.
Toán hạng bên trái nhất trở thành tham số *this ngầm định.
Tất cả các toán hạng khác trở thành tham số hàm.
44. NHP, Khoa CNTT, Trường ĐHHHVN
Khả năng và giới hạn của chồng toán tử
Phần lớn toán tử trong C++ đều có thể định nghĩa chồng, trừ các toán tử:
“::”, “.”, “?:” “ sizeof”, …
Chỉ có thể overload các toán tử đã tồn tại.
Phải giữ được thứ tự ưu tiên và tính kết hợp của toán hạng được overload.
Các toán tử sau : =, [ ], ( ), -> phải được quá tải thông qua hàm thành viên
<<, >>: phải được quá tải thông qua hàm bạn
++ và -- cần hai hàm toán tử khác nhau cho mỗi phép toán
50. NHP, Khoa CNTT, Trường ĐHHHVN
Quá tải toán tử ++, --
Toán tử ++ và – có 2 dạng sử dụng là đứng trước và đứng sau
toán hạng
Ví dụ: ++a hoặc a++ (--a hoặc a--)
Cần xây dựng 2 dạng hàm chồng cho mỗi toán tử trên
– operator++() cho dạng ++a
– operator++(int) cho dạng a++
59. Toán tử gán =
A=B; // hiểu là A.operator=(B);
B có thể là tham trị hoặc tham chiếu
Việc truyền bằng tham trị đòi hỏi sự có mặt của hàm thiết lập sao
chép, hơn thế nữa sẽ làm cho chương trình chạy chậm vì mất thời
gian sao chép một lượng lớn dữ liệu.
Vì vậy, b sẽ được truyền cho hàm operator= dưới dạng tham
chiếu.
60. Toán tử gán
DS &operator=(DS & p);//bổ sung vào khai báo lớp
DS &DS::operator=(DS &p) {
if (this !=&p){
delete v;
a=new float [spt=p.spt];
for(int i=0; i<n; i++) *(a+i)=p.(*(a+i));
}
else cout<<"Hai doi tuong la motn";
return *this;
}
Editor's Notes
#9:Con trỏ this trỏ vào đối tượng đang gọi phương thức
#19:không thể khởi tạo giá trị của nó tại đây mà phải thực hiện trong 1 không gian chung, nghĩa là nằm ngoài tất cả các khai báo lớp cũng như nằm ngoài tất cả các xử lý hàm.
#20:Xây dựng lớp DS có các hàm sắp xếp, tìm Max, Min mà ko cần phải tạo ra đối tượng (tức là có thể sắp xếp, tìm max, min, … của dãy số bình thường-ko phải đổi tượng)
#34:biểu thức a + b sẽ gọi tới một hàm cộng hai số nguyên nếu a và b thuộc kiểu int nhưng sẽ gọi tới một hàm khác nếu chúng là các đối tượng của một lớp nào đó mà chúng ta mới tạo ra.
#41:Hàm đảo dấu (-) ở trên không tác động lên toán hạng, chỉ sử dụng trong các biểu thức: ví dụ x=-y+z; thì được; nhưng –y; thì y vẫn không đổi
#44:hai phép toán ++ và -- có thể sử dụng theo hai cách khác nhau ứng với dạng tiền tố ++a, --b và dạng hậu tố a++, b--. Điều này đòi hỏi hai hàm toán tử khác nhau
#59:Việc truyền bằng tham trị đòi hỏi sự có mặt của hàm thiết lập sao chép, hơn thế nữa sẽ làm cho chương trình chạy chậm vì mất thời gian sao chép một lượng lớn dữ liệu. Vì vậy, b sẽ được truyền cho hàm operator= dưới dạng tham chiếu.
Giá trị trả về của hàm operator= phụ thuộc vào mục đích sử dụng của biểu thức gán. Chúng ta chọn giải pháp trả về tham chiếu của đối tượng đứng bên trái dấu bằng nhằm giữ hai tính chất quan trong của biểu thức gán: (i) trật tự kết hợp từ bên phải sang trái, (ii) có thể sử dụng kết quả biểu thức gán trong các biểu thức khác. Ngoài ra giải pháp này cũng hạn chế việc sao chép dữ liệu từ nơi này đi nơi khác trong bộ nhớ.