3. BM MTT&TT 3
Hàm xây dựng (Constructor)
Hàm hủy (Destructor)
Hàm xây dựng sao chép (Copy constructor)
Đối tượng là dữ liệu thành viên của một lớp
Nội dung bài giảng
4. BM MTT&TT 4
Mục đích: dùng để khởi tạo giá trị ban đầu cho đối tượng
Gán giá trị đầu cho các thuộc tính (dữ liệu thành viên)
Cấp vùng nhớ cho con trỏ thành viên.
Hàm xây dựng
class Diem {
int x, y;
public:
Diem(int a)
{ x = y = a; }
Diem(int h, int t)
{ x = h; y=t; }
….
};
class PhanSo {
int tu, mau;
public:
PhanSo()
{ tu=0; mau=1; }
PhanSo(int x)
{ tu=x; mau=1; }
PhanSo(int t, int m)
{ tu = t; mau=m; }
….
};
5. BM MTT&TT 5
Ví dụ
Hàm xây dựng
class SinhVien {
char mssv[8];
char* hoten;
int namsinh;
float diemtb;
public:
SinhVien() {
strcpy(mssv,””);
hoten = new char[50];
namsinh = 1980;
diemtb = 0;
}
SinhVien(char*,char*,int,float);
…
};
class Stack {
float *ds;
int soluong;
int vitri;
public:
Stack(int max = 10) {
soluong = max;
vitri = 0;
ds = new float[soluong];
}
Stack(float* d, int m, int n);
…
};
Cấp vùng nhớ
cho con trỏ
6. BM MTT&TT 6
Nếu không có định nghĩa hàm xây dựng:
Trình biên dịch sẽ tự động thêm vào 1 hàm xây dựng
không đối số => Hàm xây dựng mặc nhiên.
Viêc khởi tạo đối tượng không tham số đầu chỉ có 1 cách
duy nhất.
Hàm xây dựng
class Diem {
int x, y;
public:
void InDiem();
void NhapDiem();
void GanGiaTri(int, int);
int GiaTriX();
int GiaTriY();
…
};
// Định nghĩa các hàm thành viên
…
…
…
a
x
y
1000H
void main() {
Diem a;
Diem *pa = new Diem();
Diem ds1[10];
Diem *ds2 = new Diem[20];
…
}
Không có giá trị đầu
nên dễ gây ra
hiệu ứng phụ
7. BM MTT&TT 7
Nếu có định nghĩa ít nhất 1 hàm xây dựng:
Có bao nhiêu hàm xây dựng sẽ có bấy nhiêu cách khởi tạo
đối tượng theo dạng đã định nghĩa.
Chú ý: Trường hợp sử dụng đối số mặc nhiên trong hàm
xây dựng
Hàm xây dựng
void main() {
PhanSo a;
PhanSo b(3);
PhanSo c(2,5);
PhanSo d[3];
PhanSo *pa = new PhanSo;
PhanSo *pa1 = new PhanSo();
PhanSo *pa2 = new PhanSo[5];
PhanSo *pb = new PhanSo(3);
PhanSo *pc = new PhanSo(2,5);
…
}
void main() {
Stack a;
Stack b(5);
Stack c[5];
Stack *pa = new Stack();
Stack *pb = new Stack(40);
Stack *pc = new Stack[40];
float data[40];
for(int i=0;i<10;i++)
data[i]=i;
Stack d(data, 30, 10); …
}
8. BM MTT&TT 8
Trình tự tạo 1 đối tượng:
Vùng nhớ dành cho đối tượng được cấp phát (tạo ra) trước.
Hàm xây dựng được gọi để khởi tạo giá trị cho các dữ liệu
thành viên của đối tượng mới.
Hàm xây dựng
c
tu
mau
2
5
c
tu
mau
PhanSo c(2,5);
PhanSo *pa2 =
new PhanSo[5];
tu
mau
1000H
*pa2
1000
tu
mau
1000H
*pa2
1000
0
1
0
1
0
1
0
1
0
1
0
1200
5
*ds
soluong
vitri
1200H
Stack b(5);
*ds
soluong
vitri
…
…
…
9. BM MTT&TT 9
Mục đích: thu hồi các nguồn tài nguyên đang sử dụng bởi đối
tượng trước khi đối tượng bị hủy
Thu hồi vùng nhớ đã cấp phát cho con trỏ delete con
trỏ
Đóng các nguồn tài nguyên đang mở (tập tin)
Hàm hủy
class SinhVien {
char mssv[8];
char* hoten;
int namsinh;
float diemtb;
public:
SinhVien() {
strcpy(mssv,””);
hoten = new char[50];
namsinh = 1980;
diemtb = 0;
}
~SinhVien() { delete[] hoten; }
…
};
class Stack {
float *ds;
int soluong;
int vitri;
public:
Stack(int max = 10) {
soluong = max;
vitri = 0;
ds = new float[soluong];
}
~Stack() { delete[] ds; }
…
};
10. BM MTT&TT 10
Thứ tự thực hiện: gọi trước khi hủy đối tượng
Kết thúc 1 hàm mà trong đó ta có khởi tạo đối tượng.
Thu hồi vùng nhớ cho con trỏ đối tượng.
Hàm hủy
void HamMinhHoa() {
Stack a;
Stack *pa = new Stack(8);
…
delete pa;
Stack *pb = new Stack[5];
…
delete[] pb;
pb = new Stack(20);
…
}
Hàm xây dựng được gọi
Hàm hủy được gọi cho
đối tượng mà pa đang trỏ tới
Hàm xây dựng được gọi 5 lần
Hàm hủy được gọi 5 lần
Hàm hủy được gọi cho a
trước khi kết thúc hàm
HamMinhHoa()
Hàm xây dựng được gọi
11. BM MTT&TT 11
Mục đích: dùng để tạo 1 đối tượng từ 1 đối tượng đã tồn tại.
Được gọi trong các trường hợp:
Đối số của hàm là một đối tượng.
Trị trả về của hàm là 1 đối tượng.
Khởi tạo đối tượng từ một đối tượng đã có sẵn.
Hàm xây dựng sao chép
class Diem {
int x,y;
public:
Diem(int h=0, int t=0) {
x = h; y = t;
}
Diem doixung() {
return Diem(-x,-y);
}
char* trung(Diem d) {
if(x==d.x && y==d.y)
return “Trung”;
return “Ko trung”;
}
};
Diem a(1, 2), b, c(a);
b = a.doixung();
cout << a.trung(b);
12. BM MTT&TT 12
Trong cả 3 trường hợp trên, có 1 đối tượng mới được tạo ra
từ một đối tượng có sẵn
Diem c(a): tạo đối tượng c “giống” đối tượng a.
b = a.doixung(): một đối tượng “tạm” “giống” với đối
tượng Diem(-x,-y) trong hàm doixung() được tạo ra
bên trong hàm main() để gán cho b.
a.trung(b): đối tượng d, là tham số hình thức của hàm
trung() được tạo ra “giống” với đối tượng b, là tham số
thực tế trong hàm main().
Khi đó, hàm xây dựng sao chép của các đối tượng “mới” sẽ
được gọi để sao chép dữ liệu.
Hàm xây dựng sao chép
13. BM MTT&TT 13
Nếu lớp không có hàm xây dựng sao chép
Trình biên dịch sẽ tự động thêm vào cho lớp một hàm xây
dựng sao chép mặc nhiên.
Hàm này sẽ thực hiện gán tuần tự từng thuộc tính của đối
tượng mới bằng (“=“) với từng thuộc tính tương ứng của
đối tượng có sẵn.
Có thể bị sai nếu lớp có dữ liệu thành viên là con trỏ.
Hàm xây dựng sao chép
Chú ý: Phân biệt giữa trường hợp thực hiện phép
gán (“=“) với trường hợp gọi hàm xây dựng sao
chép.
Diem a(1,2), b, c(a); //gọi hàm XDSC cho c
b = a; //thực hiện phép gán cho b
14. BM MTT&TT 14
Hàm xây dựng sao chép
Stack a(5);
//gán dữ liệu cho Stack a
...
Stack b(a); //tạo b giống a
a
ds:1000
soluong:5
vitri:3
b
ds:
soluong:
vitri:
Diem a(1,2);
Diem b(a); // tạo b giống a
a
x:1
y:2
b
x:
y:
=
=
=
=
=
1
2
1000
5
3
15. BM MTT&TT 15
Cú pháp:
<Tên lớp> (const <Tên lớp>& <tên tham số> )
{ Nội dung hàm }
VD: Diem(const Diem& d) { … }
Stack(const Stack& s) { … }
SinhVien(const SinhVien& sv) { … }
Nội dung:
Gán tương ứng (=) các thành phần dữ liệu (không là con
trỏ).
Đối với dữ liệu thành viên là con trỏ: Cấp phát vùng nhớ và
sao chép nội dung vùng nhớ quản lý bởi con trỏ từ đối
tượng cho trước.
VD: Diem(const Diem& d) { x=d.x; y=d.y; }
PhanSo(const PhanSo& p) { tu=p.tu; mau=p.mau; }
Hàm xây dựng sao chép
16. BM MTT&TT 16
Hàm xây dựng sao chép
class Diem {
int x, y;
public:
Diem(int x=0, int y=0) {
this->x = x;
this->y = y;
cout << “nXD ” << this;
}
Diem(const Diem& d) {
x = d.x; y = d.y;
cout << "nXDSC: " << this;
}
Diem doixung() {
Diem kq(-x,-y);
return kq;
}
...
};
void main() {
Diem a(1,2);
Diem b(a), c;
c = a.doixung();
cout << "na: " << &a;
cout << "nb: " << &b;
cout << "nc: " << &c;
}
Đây cũng chính là nội
dung hàm XDSC mặc
nhiên
17. BM MTT&TT 17
Hàm xây dựng sao chép
class SinhVien {
char mssv[8];
char* hoten;
int namsinh;
float diemtb;
public:
…
SinhVien(const SinhVien& s) {
strcpy(mssv, s.mssv);
hoten = new char[50];
strcpy(hoten, s.hoten);
namsinh = s.namsinh;
diemtb = s.diemtb;
}
…
};
*hoten
namsinh
diemtb
1240
1974
8.14
N g u y e n … …
1240H
91 02 98 01mssv[]
*hoten
namsinh
diemtb
2760
1974
8.14
91 02 98 01mssv[]
N g u y e n … …
2760H
copy
SinhVien x(nva);
SinhVien nva; …
19. BM MTT&TT 19
Giới thiệu
Lớp là một kiểu dữ liệu do người dùng định nghĩa
=> Dữ liệu thành viên của một lớp có thể là 1 ĐT.
Đây là một cách sử dụng lại mã (reusability), trong đó
quan hệ giữa lớp sử dụng lại và lớp được sử dụng là quan
hệ “có” hay “bao gồm”.
(Cần phân biệt với tính kế thừa, quan hệ “là”).
Đối tượng là dữ liệu thành viên
20. BM MTT&TT 20
Thuộc tính của 1 lớp có thể có kiểu bất kỳ.
Thuộc tính của 1 lớp có thể là đối tượng của 1 lớp khác.
Đối tượng là dữ liệu thành viên
Sử dụng lại 1 lớp, nhưng không phải là thừa kế
class Diem {
int x, y;
public :
Diem();
Diem(int , int);
void Nhap();
void Hien();
void DoiDiem(int,int);
int GiaTriX();
int GiaTriY();
};
class DuongTron {
Diem tam;
int bankinh;
public:
DuongTron(); ...
void Ve();
void Nhap();
void
DoiDTron(int,int);
float ChuVi();
float DienTich();
};
21. BM MTT&TT 21
Cách truy xuất
Khi truy xuất đến thuộc tính là đối tượng, phải thông qua
tên của đối tượng (thuộc tính).
Lưu ý đến thuộc tính truy cập (public, private, …) của
thành phần dữ liệu và hàm thành viên của lớp tạo ra đối
tượng đó để truy xuất hợp lý.
Đối tượng là dữ liệu thành viên
void DuongTron :: Ve() {
cout<<“Tam : “; tam.Hien(); cout<<endl;
cout<<“Ban kinh : “<<bankinh<<endl;
}
void DuongTron :: Nhap() {
cout<<“Nhap tam : “<<endl; tam.Nhap();
cout<<“Nhap ban kinh : “; cin>>bankinh;
}
void DuongTron :: DoiDTron(int dx, int dy) {
tam.DoiDiem(dx, dy);
}
7
10
20
tam
bankinh
x
y
DuongTron a;
22. BM MTT&TT 22
Hàm xây dựng của đối tượng là dữ liệu thành viên
Phải khởi tạo cho thuộc tính là đối tượng theo dạng hàm
xây dựng của lớp đó: <prototype hàm XD> : <tên
ĐT>(tsố) {…}
Nếu có nhiều thuộc tính là đối tượng, khởi tạo các đối
tượng này liên tiếp nhau thông qua dấu phẩy (,).
Cú pháp này cho phép áp dụng cả với thuộc tính thường.
Đối tượng là dữ liệu thành viên
DuongTron() : tam() { bankinh=0; }
DuongTron(Diem d, int bk) : tam(d) { bankinh=bk; }
DuongTron(int x, int y, int bk) : tam(x,y) { bankinh=bk; }
DuongTron(const DuongTron& d): tam(d.tam) {bankinh=d.bankinh;}
Duongtron(): tam(), bankinh(0) {}
Duongtron(Diem d, int bk) : tam(d), bankinh(bk) {}