HÀM XÂY DỰNG, HÀM HỦY VÀ VIỆC KHỞI TẠO ĐỐI TƯỢNG 1 Chương 5... Hàm xây dựng• Mục đích: khởi tạo giá trị ban đầu cho đối tượng – Gán giá trị đầu cho các thuộc tính.. • Nếu có định nghĩa í
Trang 1HÀM XÂY DỰNG, HÀM HỦY VÀ VIỆC KHỞI TẠO ĐỐI TƯỢNG
1
Chương 5
Trang 2Nội dung
• Hàm xây dựng
• Hàm hủy
• Hàm xây dựng sao chép
• Thuộc tính của 1 lớp là đối tượng
2
Trang 3Hàm xây dựng
• Mục đích: khởi tạo giá trị ban đầu cho đối tượng
– Gán giá trị đầu cho các thuộc tính.
– Cấp vùng nhớ cho con trỏ thành viên.
3
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; }
….
};
Trang 4• Ví dụ:
4
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,fl
oat);
… };
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);
… };
Hàm xây dựng
Cấp vùng nhớ
cho con trỏ
Trang 5• Nếu không có định nghĩa hàm xây dựng:
– Mặc nhiên sẽ tự động có 1 hàm xây dựng không tham số – Chỉ có 1 cách khởi tạo đối tượng theo dạng không tham số.
5
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ụ
Hàm xây dựng
Trang 6• 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.
6
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);
… }
Hàm xây dựng
Trang 7• Trình tự thực hiện:
– Đối tượng được tạo ra trước.
– Hàm xây dựng sẽ gọi sau trên đối tượng.
7
c
tu mau
2 5
c
tu mau
PhanSo c(2,5);
PhanSo
*pa2 = new
PhanSo[5];
tu mau
1000H
*pa2
100 0
tu mau
1000H
*pa2
100 0
0 1
0 1
0 1
0 1
0 1
0
120 0 5
*ds soluong vitri
1200H
Stack
b(5);
*ds soluong vitri
…
…
…
Hàm xây dựng
Trang 8Hàm hủy • Mục đích: thu hồi vùng nhớ đã cấp cho con
trỏ là dữ liệu thành viên => delete con trỏ
8
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; }
… };
Trang 9• 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.
9
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
Hàm hủy
Trang 10Hàm xây dựng sao chép
• Tại sao cần hàm xây dựng sao chép?
– Khởi tạo 1 đối tượng có giá trị giống 1 đối tượng khác – Khác với phép gán (dấu =)
• Nếu không định nghĩa hàm xây dựng sao chép:
– Ngôn ngữ sẽ tự động tạo ra cho ta: nội dung là gán (=) tương ứng từng thành phần.
– Không chính xác khi có dữ liệu thành viên là con trỏ.
10
Trang 11Hàm xây dựng sao chép
*ds soluong vitri
130 0 8 3
1300H
Stack a(8);
…
a Stack b(a);
*ds soluong vitri
130 0 8 3
b
2 con trỏ sẽ
trỏ cùng 1 địa chỉ nếu không định nghĩa hàm xây dựng sao chép
Trang 12• Cú pháp: <Tên lớp> ( const <Tên lớp> & )
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ỏ) – Cấp vùng nhớ và sao chép nội dung vùng nhớ 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;
Hàm xây dựng sao chép
Trang 13• Ví dụ:
13
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 … …
1 2 4 0 H
SinhVien nva; …
9
1 2 0 8 9 1 \ 0 mssv[]
2760 1974 8.14
9
1 2 0 8 9 1 \ 0
N g u y e n … …
2 7 6 0 H
c o p y
SinhVien x(nva);
Hàm xây dựng sao chép
*hoten namsinh diemtb mssv[]
Trang 14• Ví dụ:
14
class Stack {
float * ds;
int soluong;
int vitri;
public :
…
Stack( const Stack & s) {
soluong = s.soluong;
vitri = s.vitri;
ds = new float [soluong];
for ( int i=0; i<vitri; i++) ds[i]=s.ds[i];
}
…
};
*ds soluong vitri
130 0 8 3
4
3 2
1 4
… …
1 3 0 0 H
a Stack a(8); …
Stack b(a);
157 0 8 3
4
3 2
1 4
… …
1 5 7 0 H
b
copy
Hàm xây dựng sao chép
*ds soluong vitri
Trang 15• Sử dụng trong các trường hợp:
– Đối tượng được truyền theo giá trị của đối số 1 hàm.
– Trị trả về của hàm là 1 đối tượng.
– Tạo ra 1 đối tượng có giá trị giống 1 đối tượng cho trước.
15
class A {
int x;
public :
A () { x=0; }
A ( const A& a) {
x=a.x;
}
void Hien() {
cout <<“x=“<<x;
} };
A HamThu( A x) {
A y(x);
return y;
}
void main() {
A a,b;
b = HamThu(a);
A c = b;
A *d = new A(c);
}
Có bao nhiêu hàm xây dựng sao chép được gọi?
Hàm xây dựng sao chép
Trang 16Thuộc tính của 1 lớp là đối tượng
• Giới thiệu:
– 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.
16
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();
};
Trang 17• 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 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ý.
Thuộc tính của 1 lớp là đối tượng
Trang 18Void 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;
Thuộc tính của 1 lớp là đối tượng
Trang 19• Hàm xây dựng:
– 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 đó.
19
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;}
Thuộc tính của 1 lớp là đối tượng
Trang 20• Hàm xây dựng:
■ 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.
20
Duongtron() : tam(), bankinh(0)
{}
Duongtron(Diem d, int bk) : tam(d), bankinh(bk)
{}
Thuộc tính của 1 lớp là đối tượng