C++ và Lập trình hướng đối tượng - Chương 4: Hàm tạo, hàm hủy và các vấn đề liên quan

Chương này trình bầy một số vấn đề có tính chuyên sâu hơn về lớp như:

+ Hàm tạo (constructor)

+ Hàm huỷ (destructor)

+ Toán tử gán và hàm tạo sao chép

+ Mối liên quan giữa hàm tạo và đối tượng thành phần

+ Các thành phần tĩnh

+ Lớp bạn, hàm bạn

+ Đối tượng hằng

+ Phương thức inline

 

doc44 trang | Chuyên mục: C/C++ | Chia sẻ: dkS00TYs | Lượt xem: 1745 | Lượt tải: 0download
Tóm tắt nội dung C++ và Lập trình hướng đối tượng - Chương 4: Hàm tạo, hàm hủy và các vấn đề liên quan, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
một thành phần (thuộc tính hoặc phương thức) của đối tượng thứ i, ta dùng một trong các mẫu viết sau:
q[i].tên_thành_phần
(q+i)-> tên_thành_phần
- Để biểu thị đối tượng thứ i, ta dùng một trong các mẫu viết sau:
q[i]
*(q+i)
11.3. Bài toán sắp xếp thí sinh
Trong mục 10.4. đã sử dụng mảng đối tượng để giải quyết bài toán: Nhập một danh sách thí sinh, sắp xếp danh sách theo thứ tự giảm của tổng điểm. Dưới đây sẽ đưa ra phương án mới bằng cách dùng con trỏ và cấp phát bộ nhớ cho các đối tượng. Chương trình chỉ thay đổi hàm main() như sau:
void main()
{
TS *ts;
int n, i, j;
clrscr();
cout << "\n So thi sinh: " ;
cin >> n;
ts = new TS[n+1];
for (i=1; i<= n; ++i)
ts[i].nhap(i);
cout <<"\n Danh sach nhap vao:";
for (i=1; i<= n; ++i)
ts[i].in();
for (i=1; i<n ; ++i)
for (j=i+1 ; j<=n; ++j)
if (ts[i].gettd() < ts[j].gettd())
ts[i].hv(ts[j]);
cout <<"\n\n Danh sach sau khi sap xep:";
for (i=1; i<= n; ++i)
ts[i].in();
getch();
}
220	221
Nhận xét: Sự khác biệt giữa hàm main mới và hàm main trong 10.4 là rất ít.
11.4. Danh sách móc nối
Chương trình dưới đây định nghĩa lớp tự trỏ TS (lớp có thuộc tính kiểu *TS). Lớp này được dùng để tổ chức danh sách móc nối. Chương trình nhập một danh sách thí sinh và chứa trong một danh sách móc nối. Sau đó duyệt trên danh sách này để in các thí sinh trúng tuyển. So với lớp TS nêu trong mục 10.4, lớp TS ở đây có một số điểm khác như sau:
+ Thêm thuộc tính:
TS *dc; // Dùng để chứa địa chỉ của một đối tượng kiểu TS
+ Thêm các phương thức:
void setdc(TS *dc1) ; // Gán dc1 cho thuộc tính dc
TS *getdc() ; // Nhận giá trị của dc
 + Phương thức nhap trong chương trình trước có kiểu void nay sửa là: 
int nhap(int i);
Phương thức trả về 1 nếu họ tên nhập vào khác trống, trả về 0 nếu trái lại.
+ Bỏ đi các phương thức không dùng đến như: Toán tử gán, hoán vị.
//CT4_16.CPP
// Danh sách móc nối
// Lop TS (thi sinh)
#include 
#include 
#include 
#include 
#include 
class TS
{
private:
char *ht;
double td;
TS *dc;
public:
TS()
{
ht = new char[20];
td = 0;
dc=NULL;
}
~TS()
{
delete ht; dc=NULL ;
}
int nhap(int i);
void in();
double gettd()
{
return td;
}
void setdc(TS *dc1)
{
dc=dc1;
}
TS *getdc()
{
return dc;
}
222	223
} ;
void TS::in()
{
cout << "\nHo ten: " << ht << " Tong diem: " << td;
}
int TS::nhap(int i)
{
cout << "\nNhap thi sinh " << i ;
cout << "\nHo ten (Bấm Enter để kết thúc nhập): " ;
fflush(stdin);
gets(ht);
if (ht[0]==0) return 0;
cout > td;
dc=NULL;
return 1;
}
void main()
{
int i=0;
TS *pdau,*p,*q;
pdau=NULL;
clrscr();
while(1)
{
q=new TS;
++i;
if (q->nhap(i)==0)
{
delete q; break;
}
if (pdau==NULL)
pdau = p = q;
else
{
p->setdc(q) ;
p = q;
}
}
/* In */
double diemchuan;
cout << "\nDiem chuan: " ;
cin >> diemchuan;
cout <<"\nDanh sach trung tuyen:" ;
p=pdau;
while (p!=NULL)
{
if (p->gettd()>=diemchuan)
p->in();
p = p->getdc();
}
getch();
}
Đ 12. Đối tượng hằng, phương thức hằng
+ Cũng giống như các phần tử dữ liệu khác, một đối tượng có thể được khai báo là hằng bằng cách dùng từ khoá const. Ví dụ:
class DIEM
{
private:
int x, y;
224	225
int m; 
public:
DIEM()
{
x = y = m = 0;
}
DIEM(int x1, int y1, int m1=15)
{
x= x1; y= y1; m= m1;
}
...
} ;
const DIEM d = DIEM(200,100); // Khai báo đối tượng hằng
+ Khi khai báo cần sử dụng các hàm tạo để khởi gán giá trị cho đối tượng hằng. Giá trị khởi tạo có thể là các hằng, các biến, các biểu thức và các hàm, ví dụ:
int x0=100, y0=50; m0 =4;
const DIEM d5 = DIEM(x0 + getmaxx()/2, y0 + getmaxy()/2, m0);
+ Các phương thức có thể sử dụng cho các đối tượng hằng là hàm tạo và hàm huỷ. Về lý thuyết các đối tượng hằng không thể bị thay đổi, mà chỉ được tạo ra hoặc huỷ bỏ đi.
Khi dùng một phương thức cho đối tượng hằng, thì CTBD (Chương trình biên dich) sẽ cảnh báo (warning):
Non-const function called for const object
Tuy nhiên, chương trình EXE vẫn được tạo và khi thực hiện chương trình, thì nội dung các đối tượng hằng vẫn bị thay đổi. Chương trình dưới đây sẽ minh hoạ điều này. Chương trình đưa vào lớp PS (phân số). Phương thức toán tử ++ vẫn có thể làm thay đổi đối tượng hằng (mặc dù khi biên dịch có 3 cảnh báo).
//CT4_19.CPP
// doi tuong const
// Lop PS (phan so)
#include 
#include 
#include 
#include 
class PS
{
private:
int t,m;
public:
PS()
{
t = m = 0;
}
PS(int t1, int m1)
{
t = t1; m = m1;
}
PS operator++()
{
t += m ;
return *this ;
}
void in()
{
cout << "\nPS= " << t << "/" << m;
}
void nhap()
{
226	227
cout << "\n Nhap tu va mau: " ;
cin >> t >> m;
}
} ;
void main()
{
int t1=-3, m1=5;
const PS p = PS(abs(t1)+2,m1+2); // Khai báo đối tượng hằng
clrscr();
p.in();
++p;
p.in();
getch();
}
+ Phương thức const
Để biến một phương thức thành const ta chỉ việc viết thêm từ khoá const vào sau dòng đầu của phương thức. 
Chú ý: Nếu phương thức được khai báo bên trong và định nghĩa bên ngoài lớp, thì từ khoá const cần được bổ sung cả trong khai báo và định nghĩa phương thức.
Trong thân phương thức const không cho phép làm thay đổi các thuộc tính của lớp. Vị vậy việc dùng phương thức const cho các đối tượng hằng sẽ đảm bảo giữ nguyên nội dung của các đối tượng hằng.
Đương nhiên các phương thức const vẫn dùng được cho các đối tượng khác.
Ví dụ sau về lớp PS (phân số) minh hoạ việc dùng phương thức const.
// Đối tượng const
// Phương thức const
// Lop PS (phan so)
#include 
#include 
#include 
#include 
class PS
{
private:
int t,m;
public:
PS()
{
t = m = 0;
}
PS(int t1, int m1)
{
t = t1; m = m1;
}
PS operator++()
{
t += m ;
return *this ;
}
void in() const ;
void nhap()
{
cout << "\n Nhap tu va mau: " ;
cin >> t >> m;
}
228	229
} ;
void PS::in() const
{
cout << "\nPS= " << t << "/" << m;
}
void main()
{
int t1=-3, m1=5;
const PS p = PS(abs(t1)+2,m1+2);
PS q;
clrscr();
q.nhap();
p.in();
q.in();
getch();
}
Đ 13. Hàm bạn, lớp bạn
13.1. Hàm bạn (xem mục Đ6, chương 3) của một lớp, tuy không phải là phương thức của lớp, nhưng có thể truy nhập đến các thành phần riêng (private) của lớp. Một hàm có thể là bạn của nhiều lớp.
13.2. 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. 
13.3. 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
class A;
class B ;
class C;
// Định nghĩa các lớp
class A
{
...
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
{
...
friend class A ; // Lớp A là bạn của B
friend class C ; // Lớp C là bạn của B
...
};
class C
{
...
friend class B ; // Lớp B là bạn của C
...
};
13.4. Ví dụ
Chương trình dưới đây có 2 lớp:
MT (ma trận vuông)
230	231
VT (véc tơ)
Lớp MT là bạn của VT và lớp VT là bạn của MT. Trong chương trình sử dụng các phương thức trùng tên:
2 phương thức nhap():
nhập ma trận
nhập véc tơ
2 phương thức in():
in ma trận
in véc tơ
4 phương thức tich():
tích ma trận với ma trận, kết quả là ma trận
tích ma trận với véc tơ, kết quả là véc tơ
tích véc tơ với ma trận, kết quả là véc tơ
tích véc tơ với véc tơ, kết quả là số thực
Nội dung chương trình là:
+ Nhập các ma trận A, B, C
+ Nhập các véc tơ
+ Tính tích D = AB
+ Tính tích u = Dy
+ Tính tích v = xC
+ Tính tích s = vu
//CT4_17.CPP
// Lop ban
// Lop MT , lop VT
#include 
#include 
class MT;
class VT;
class MT
{
private:
double a[10][10];
int n;
public:
friend class VT;
MT()
{
n=0;
}
void nhap();
void in();
VT tich(const VT &y);
MT tich(const MT &b) ;
} ;
class VT
{
private:
double x[10];
int n;
public:
friend class MT;
VT()
{
n=0;
}
void nhap();
void in();
VT tich(const MT &b);
double tich(const VT &y) ;
232	233
} ;
void MT::nhap()
{
cout << "\n Cap ma tran: " ;
cin >> n;
for (int i=1; i<=n; ++i)
for (int j=1; j<=n; ++j)
{
cout << "\nPhan tu hang " << i << " cot " << j << " = " ;
cin >> a[i][j];
}
}
void MT::in()
{
for (int i=1; i<=n; ++i)
{
cout << "\n" ;
for (int j=1; j<=n; ++j)
cout << a[i][j] << " " ;
}
}
void VT::nhap()
{
cout << "\n Cap vec to: " ;
cin >> n;
for (int i=1; i<=n; ++i)
{
cout << "\nPhan tu thu " << i << " = " ;
cin >> x[i];
}
}
void VT::in()
{
for (int i=1; i<=n; ++i)
cout << x[i] << " " ;
}
VT MT::tich(const VT &y)
{
VT z;
int i,j;
for (i=1; i<=n; ++i)
{
z.x[i] = 0.0 ;
for (j=1; j<=n; ++j)
z.x[i] += a[i][j]*y.x[j];
}
z.n = n;
return z;
}
MT MT::tich(const MT &b)
{
MT c;
int i,j,k;
for (i=1; i<=n; ++i)
for (j=1; j<=n; ++j)
{
c.a[i][j] = 0.0 ;
for (k=1; k<=n; ++k)
c.a[i][j] += a[i][k]*b.a[k][j];
}
c.n = n;
return c;
234	235
}
VT VT::tich(const MT &b)
{
VT z;
int i,j;
for (j=1; j<=n; ++j)
{
z.x[j] = 0.0 ;
for (i=1; i<=n; ++i)
z.x[j] += b.a[i][j]*x[i];
}
z.n = n;
return z;
}
double VT::tich(const VT &y)
{
double tg=0.0;
for (int i=1; i<=n; ++i)
tg += x[i]*y.x[i];
return tg;
 }
void main()
{
MT a,b,c;
VT x,y;
clrscr();
cout << "\nMa tran A";
a.nhap();
cout << "\nMa tran B";
b.nhap();
cout << "\nMa tran C";
c.nhap();
cout << "\nvec to X";
x.nhap();
cout << "\nvec to Y";
y.nhap();
MT d= a.tich(b);
VT u = d.tich(y);
VT v = x.tich(c);
double s = v.tich(u);
cout << "\n\nVec to v\n";
v.in();
cout << "\n\nMa tran D";
d.in();
cout << "\n\nVec to y\n";
y.in();
cout << "\n\nS= vDy = " << s;
getch();
}
236	

File đính kèm:

  • docC++ và Lập trình hướng đối tượng - Chương 4 Hàm tạo, hàm hủy và các vấn đề liên quan.DOC