Bài t ậ p l ậ p trình hướ ng ng đố i t ượ ng C++ ượ ng
I. DẠNG BÀI TẬP MÔ TẢ BẰNG LỜ I. I. ớ p, các mố i quan hệ gi ữ ữa các l ớ ớ p đượ c đề bài mô t ả bằng l ờ ờ i i Toàn bộ các l ớ một cách chi ti ế nh đượ c các l ớ ết.t . D ạng này d ễ ễ dàng xác đị nh ớ p c ủa bài và m ố i quan hệ ữa chúng, các thu ộc tính và ph ươ ng ớ p. Do vậ y ta d ễ ễ dàng vẽ một gi ữ ng thứ c trong mỗ i l ớ ơ đồ cho mỗ i bài (n ế u cần). sơ đồ Sau đ ây ây là m ột số bài t ậ p ví d ụ:
Bài 1.1: Xây dựng lớ p Person gồm các thông tin: H ọ và tên, Ngày sinh, Quê quán. Sau đó, xây dựng l ớ p d ẫn xu ất “K ỹ sư” ngoài các thông tin c ủa l ớ p Person, lớ p k ỹ sư còn có các thông tin v ề: Ngành học, Năm tốt nghiệ p (int) và các ph ươ ng ng thức: Phươ ng ng thức nhậ p: nhậ p các thông tin c ủa k ỹ sư. Phươ ng ng thức xuất: xuất các thông tin lên màn hình. Xây dựng chươ ng ng trình chính nh ậ p p vào một danh sách các k ỹ sư. In danh sách của các k ỹ sư lên màn hình và thông tin của các k ỹ sư tốt nghiệ p gần đây nhất (năm tốt nghiệ p lớ n nhất). #include #include #include #include #include class Person { public: char HT[30]; char NS[30]; char Q[30]; }; class Kysu:public Person { public: char NH[30]; int NTN; void nhap(); void xuat(); }; void Kysu::nhap() { cout<<"Ho ten: ";gets(HT);fflush(stdin); cout<<"Ngay sinh: ";gets(NS);fflush(stdin); cout<<"Que quan: ";gets(Q);fflush(stdin); cout<<"Nganh hoc: ";gets(NH);fflush(stdin); cout<<"Nam tot nghiep: ";cin>>NTN; } void Kysu::xuat()
Bài t ậ p l ậ p trình hướ ng ng đố i t ượ ng C++ ượ ng
{ cout<<"Ho ten: "<>n; for(i=0;iMax) Max=a[i].NTN; cout<<"Ky su co nam tot nghiep gan day nhat la: \n"; for(i=0;i
Xây dựng chươ ng ng trình chính nh ậ p vào thông tin của n máy in kim và m máy in Laser. Xu ất các thông tin đó lên màn hình. #include #include #include #include class Mayin { public: CN: Tr ần Xuân Thứ c
Bài t ậ p l ậ p trình hướ ng ng đố i t ượ ng C++ ượ ng
cout<<"Nam sx: "<>n; cout<<"May in kim:\n"; for(i=0;i>m; cout<<"May in laser:\n"; for(i=0;i
Bài 1.3. Xây dựng lớ p PERSON gồm các thông tin sau: Hoten (char[50]), Ngaysinh (char[12]), Quequan (char[100]) và xây dựng lớ p DIEM g ồm: Diểmtoan (int), Diemly (int), Điểmhoá (int). Xây dựng lớ p HOCSINH k ế thừa từ 2 lớ p trên có thêm d ữ liệu: Lop (char [30]), Tongdiem (int) và các phươ ng 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 cả 3 lớ p trên đều có phươ ng ng thức thiết lậ p để khở i tạo các d ữ liệu là số thì giá tr ị = 0, dữ liệu là xâu thì giá tr ị = “”. Phải viết chươ ng ng trình chính để minh hoạ sử dụng lớ p vừa xâu dựng. #include #include #include #include class Person { public: char HT[50],NS[12],QQ[100]; void nhap();
cout<<"Diem hoa: ";cin>>Dhoa; } void Diem::xuat() { cout<<"Diem toan: "<>n; for(int i=0;i
II. CÀI ĐẶT THEO SƠ ĐỒ LỚ P. Bài 2.1. Cài đặt các l ớ p theo biểu đồ sau: Máy tính
(vớ i input và output là các ph ươ ng thức nhậ p, xuất thông tin của các thu ộc tính của lớ p). Viết chươ ng trình chính nhậ p vào danh sách n máy tính. In ra thông tin c ủa các máy tính c ủa nhà sản xuất IBM. S ắ p xế p danh sách các máy tính theo chi ều tăng dần của giá thành và in danh sách
đã sắ p ra màn hình. Xoá mọi máy tính của hãng Intel sản xuất và in danh sách k ết quả ra màn hình. #include #include #include #include class NhaSX { char TenNSX[30]; char DC[30]; friend class May; friend class Maytinh; friend void In(Maytinh *a,int n); friend void Xoa(Maytinh *a,int *n); }; class May { public: char NH[30]; NhaSX NSX; float GT; void nhap(); void xuat(); }; class Maytinh:public May { float TD; int DLR; int DLHDD; public: void nhap(); void xuat();
for(i=0;i
Bài 2.2. Cài đặt các l ớ p theo biểu đồ sau: Máy tính - Tốc độ - Dung lượ ng RAM - Dung lượ ng HDD void input(); void output();
Máy - Nhãn hiệu - Nhà sản suất - Giá thành void input(); void output();
Nhà sản xuất private: - Tên NSX - Địa chỉ
public:
void input(); void output();
(vớ i input và output là các ph ươ ng thức nhậ p, xuất thông tin của các thu ộc tính của lớ p). Viết ch ươ ng trình chính nhậ p vào danh sách n máy tính. In ra thông tin c ủa các máy tính của nhà xản su ất Intel. S ắ p x ế p danh sách các máy tính theo chiều gi ảm d ần của giá thành và in danh sách đã sắ p ra màn hình. Cho biết giá thành trung bình c ủa mỗi chiếc máy tính? #include #include #include #include class NhaSX { char TenNSX[30]; char DC[30]; friend class May; friend class Maytinh; friend void In(Maytinh *a,int n); friend void Xoa(Maytinh *a,int *n); }; class May { CN: Tr ần Xuân Thứ c
Viết chươ ng trình chính nhậ p vào 1 vé ngườ i lớ n và 1 vé tr ẻ em. In ra thông tin của các vé đó kèm theo giá vé. #include #include #include #include #include class Ve { public: int Giagoc; char Ngay[30]; void nhap(); void xuat(); }; class VeNL:public Ve { int Giam; float Giave; public: void nhap(); void xuat(); }; class VeTE:public Ve { int Giam; float Giave; public: void nhap(); void xuat(); }; void Ve::nhap() { cout<<"Gia goc: ";cin>>Giagoc; cout<<"Ngay: ";gets(Ngay);fflush(stdin); } void Ve::xuat() { cout<<"Gia goc: "<>Giam; Giave=Giagoc-(Giagoc*Giam)/100;
} void VeNL::xuat() { Ve::xuat(); cout<<"Giam: "<>Giam; Giave=Giagoc-(Giagoc*Giam)/100; } void VeTE::xuat() { Ve::xuat(); cout<<"Giam: "<
Bài 2.4. Viết chươ ng trình mô phỏng hoạt động của một bộ máy vi tính g ồm các bộ phận: Nguồn (Power), Hệ điều hành (OS), Màn hình (Monitor), CPU theo s ơ đồ sau (nội dung các phươ ng thức thí sinh tự xác định sao cho thoả mãn yêu cầu trong chươ ng trình chính): Power Bật_Nguồn():
CPU Nguon:
void
Power HĐH: OS
Tắt_Nguồn(): void
Computer Màn_Hình: Monitor Cpu: CPU Cài_ Đặt(Tên: char*): void
Chươ ng trình chính sinh ra một chiếc máy tính, cài đặt hệ điều hành cho máy tính đó (vớ i tên hệ điều hành đượ c gán là WINXP). Bật CPU của máy (gồm bật nguồn: thông báo nguồn đã bật; khở i động hệ điều hành: thông báo hệ điều hành đã khở i động kèm theo tên hệ điều hành). Đặt độ sáng cho màn hình máy tính v ớ i giá tr ị bất k ỳ (có thông báo độ sáng đượ c đặt ra màn hình). T ắt CPU ( bao g ồm tắt hệ điều hành, tắt nguồn). #include #include #include #include class Power { public: void Bat_Nguon(); void Tat_Nguon(); }; class OS { char Ten[30]; public: void Khoi_Dong(); void Tat_HDH(); friend class Computor; }; class CPU { Power Nguon; OS HDH; friend class Computor; }; class Monitor { int Do_Sang; public: void Datdosang(int ds); }; class Computor { Monitor Man_Hinh;
{ Computor x; x.Cai_Dat("WINXP"); x.Bat_CPU(); x.Datdosang(15); x.Tat_CPU(); getch(); } Bài 2.5. Cài đặt lớ p theo sơ đồ sau:
Person
Hospital
Person
Họ tên Tuổi
Tên BV Địa chỉ
Họ tên Tuổi
Nhap( )
Nhap( )
Xuat
Xuat
Nhậ p vào một danh sách gồm n bệnh nhân. Sắ p xế p danh sách theo chi ều tăng dần của tuổi. In ra các b ệnh nhân đượ c điều tr ị trong bệnh viện có giám đốc bệnh viện là Hoàng Hà. #include #include #include #include class Person { public: char HT[30]; int Tuoi; void nhap(); void xuat(); }; class Hospital { char TenBV[30],DC[30]; Person GD; friend class BN; friend void IN(BN *a,int n); }; class BN:public Person { char TS[30],CD[30]; Hospital BV; public: void nhap(); CN: Tr ần Xuân Thứ c
void main() { int n; Phieu x[100]; cout<<"n= ";cin>>n; for(int i=0;i
PHIẾU KHÁM BỆNH Mã phiếu: PH01. Tên bệnh nhân: Hoàng Hà Địa chỉ: Thái Bình Bác sỹ chẩn đoán: Đinh Thị Lan
Mã triệu chứ ng TC005 TC09 TC010 p K ết luận: Viêm xoang c ấ
Ngày khám: Nguyễ n H ải Hà Giớ i tính: Nam Tuổi: 18 Tiền sử bệnh: Viêm mũi d ị ứ ng Nơ i công tác: Phòng khám Đ K- BV Bạch Mai
Tên triệu chứ ng Nhức đầu váng vất về chiều Sốt âm ỷ về đêm Bờ dướ i khóe mắt bị phù nề
#include #include #include #include #include class BN { char TenBN[30]; char GT[20]; int Tuoi; char DC[30],TSB[30]; public: void nhap(); void xuat(); }; class BS { char TenBS[30]; char NoiCT[30]; public:
} void Phieu::xuat() { cout<<" PHIEU KIEM KE TAI SAN cout<<"Ma phieu: "<
\n";
Bài 3.4. Viết chươ ng trình cho phép nhậ p, xuất phiếu sau: PHIẾU XUẤT SÁCH Mã phiếu: PH01. Mã khách hàng: KH005 Địa chỉ: Minh khai Thông tin sách xuất:
Ngày nhậ p: 01/02/2007 Tên KH: Tr ườ ng tiể u học Minh Khai Số ĐT: 0987215828
void Sach::xuat() { cout<>n; for(int i=0;i
Bài 3.5. Viết chươ ng trình quản lý việc đặt phòng khách sạn. Yêu cầu các thuộc tính đều đặt phạm vi truy cậ p private và ch ươ ng trình đáp ứng đượ c các chức năng sau: - Tạo một phiếu đặt phòng: cho phép nhậ p các thông tin v ề mã phiếu, ngày đặt, ngày đến (thuê), các thông tin v ề khách hàng, các thông tin v ề phòng đặt. - In ra phiếu đặt phòng theo mẫu sau: PHIẾU ĐẶT PHÒNG Mã phiếu: PH01. Mã khách hàng: KH005 CN: Tr ần Xuân Thứ c
Ngày đặt: 01/02/2007 Ngày đến: 15/02/2007 Tên KH: Tr ần Thanh Hà - 31-
int t=0; for(i=0;i
IV. CÁC DẠNG BÀI TẬP KHÁC Ngoài vi ệc l ắ m vữ ng cách cài đặ t các bài t ậ p thông th ườ ng, ta c ần bổ xung có tính ch ấ t đặ c biệt. Các l ớ p có thêm thêm một số kiế n thứ c để cài đặ t các l ớ p thuộc loại này. phươ ng thứ c toán t ử là nhữ ng l ớ p
1. Định ngh ĩ a hàm toán tử theo lập trình cấu trúc a. Phân loại toán t ử Một biểu thức đượ c tạo nên từ các toán tử (phép toán) và các toán h ạng (số hạng). Ví dụ biểu th ức Q = 2*x + b thì các toán tử * và + cùng vớ i các toán h ạng 2, x và b đượ c sử dụng. Các toán tử có thể tạm chia làm hai lo ại: Toán tử một ngôi: Là những toán tử thực hiện trên một toán hạng. Thuộc loại này có phép phủ định (!), Phép tăng 1 đơ n vị (++), giảm một đơ n vị (--), phép đổi dấu… Toán tử hai ngôi: Là nhũng toán tử thực hiện trên 2 toán hạng. Thuộc loại này bao gồm các toán tử cộng (+), tr ừ (-), nhân (*), chia (/)…. Trong lậ p trình, các toán tử cộng, tr ừ, nhân, chia,… trên các toán h ạng thông thườ ng đã đượ c định ngh ĩ a sẵn, ta chỉ việc sử dụng. Tuy nhiên, một số toán tử trên các toán hạng đặc biệt lại chưa đượ c định ngh ĩ a. Ví dụ: phép cộng , trù, nhân, chia hai phân số, phép cộng, tr ừ, nhân, chia hai s ố phức .v.v.. Chươ ng này nhằm giúp ta cách th ức cài đặt các phép toán ch ưa đượ c định ngh ĩ a trong lậ p trình như vậy. Sau khi cài đặt, ta có th ể sử dụng chúng như các toán tử thông thườ ng. b. Hàm toán t ử trong l ậ p trình cấ u trúc. Ta tr ở lại vớ i phươ ng pháp lậ p trình cấu trúc. Khi đó, một hàm toán t ử có đặc điểm sau: - Hàm toán t ử đượ c cài đặt tươ ng tự hàm thông thườ ng, chỉ khác ở tên hàm và cách sử dụng. - Tên hàm: đượ c viết theo d ạng: operator - Cú pháp của hàm: operator (các đối số) { CN: Tr ần Xuân Thứ c
Ví dụ: Hàm toán tử cộng hai số thực bất k ỳ đượ c viết như sau: float operator + (float x, float y) { return x + y; }
Cách sử dụng hàm toán tử : Có hai cách gọi một hàm toán tử. Cách 1: gọi như hàm thông thườ ng. VD: để cộng hai số thực a, b ta có th ể viết: cout<< “Tong cua hai so a va b la” << operator+(a,b); Cách 2: gọi như một toán tử: Ta có th ể sử dụng hàm toán tử như một toán tử, tức là ta có th ể viết: cout<< “Tong cua hai so S1 va S2 la” << S1 + S2; Phép cộng trên sẽ gọi tớ i hàm toán tử cộng đã định ngh ĩ a. VD: Một số phức có dạng: + i * . Cho hai số phức X = a + i*b và Y = c + i * d . Khi đó X + Y sẽ cho số phức có dạng: X+Y = (a+c) + i * (b + d) . Hãy định ngh ĩ a hàm toán tử để thực hiện cộng hai số phức bất k ỳ. typedef struct SP -
{ float Phanthuc; float Phanao; }; //Dinh nghia ham toan tu cong hai so phuc
void main() { // Khai bao hai so phuc x va y va so phuc tong T SP x,y, T; x.Phanthuc = 2; x.Phanao = 3; y.Phanthuc= 3; y.Phanao = 5; //Cong hai so phuc va in ket qua len man hinh T = operator+(x, y) ; //Co the viet T = x + y cout<<"Ket qua "<
CN: Tr ần Xuân Thứ c
Chú ý: Thay bằng viết T = operator+(x, y) ; ta có thể viết: T = x + y; như cộng hai số thực thông thườ ng do đã định ngh ĩ a hàm toán tử cộng hai số phức ở trên. 2. Định ngh ĩ a phươ ng thứ c toán tử Trong Lậ p trình Hướ ng đối t ượ ng, khi muốn một ph ươ ng thức là phươ ng thức toán tử, ta cài đặt thế nào? Khi đã cài đặt chúng thì sử dụng thế nào? Ta nhận thấy: Phươ ng thức toán tử một ngôi không có đối vào. Như vậy việc đổi dấu sẽ thực hiện trên số phức nào? Thực chất phươ ng thức toán tử đổi dấu trên đã bao gồm một đối mặc định, đó là con tr ỏ this. Con tr ỏ this luôn là đối m ặc định c ủa các phươ ng thức toán tử. Nh ư vậy, hai cách viết sau là tươ ng đươ ng tg.Phanthuc = -Phanthuc; tg.Phanthuc = -this -> tg.Phanao = -Phanao; Phanthuc; tg.Phanao = -this -> Phanao; Khi sử dụng phươ ng thức toán tử một ngôi ta cũng có 2 cách như vớ i hàm toán tử. Như vậy, hai cách viết sau là tươ ng đươ ng:
-
SoPhuc y = x.operator-(); SoPhuc y = -x; b. Cài đặ t phươ ng thứ c toán t ử hai ngôi Như đã biết, trong phươ ng thức toán tử, con tr ỏ this luôn là một đối số mặc định. Như vậy, vớ i phươ ng thức toán tử hai ngôi, thay vì có hai đối vào, ta ch ỉ cần một đối, đối còn lại là con tr ỏ this. Tươ ng tự như phươ ng thức toán tử một ngôi, ta nhận thấy: Phươ ng thức toán tử hai ngôi có 1 đối vào. Đối vào còn lại chính là con tr ỏ this. Con tr ỏ this luôn là đối m ặc cách viết sau là tươ ng đươ ng
tg.Phanthuc = this -> Phanthuc + y.Phanthuc; tg.Phanao = this -> Phanao + y.Phanao;
Khi sử dụng phươ ng thức toán tử hai ngôi ta cũng có 2 cách như vớ i hàm toán tử. Như vậy, hai cách vi ết sau là tươ ng đươ ng:
-
SoPhuc T = x.operator+(y);
SoPhuc T = x + y
3. Cài đặt một số phươ ng thứ c toán tử : Bài 4.2. Hãy xây dựng lớ p phân số vớ i các thuộc tính Tử số và Mẫu số và các phươ ng thức: Toán tử nhậ p (>>) và xuất (<<) đưa phân số ra màn hình (dướ i dạng Tử số/ Mẫu số). Phươ ng thức khở i tạo, khở i gán Tử số và Mẫu số. CN: Tr ần Xuân Thứ c
- Hãy xây dựng một lớ p Phân số vớ i các thuộc tính Tử số, Mẫu số và các phươ ng thức: + Nhậ p phân số: Nhậ p các giá tr ị của tử số và mẫu số. + Xuất phân số: đưa phân số ra màn hình (dướ i dạng Tử _Số/ Mẫu_số). + Toán tử nhân hai phân số (x). - Vi ết ch ươ ng trình chính nhậ p hai phân số, đưa ra màn hình phân số là tích của hai phân số vừa nhậ p. #include #include #include class PS { int TS,MS; public: friend istream & operator>>(istream & x,PS & y); friend ostream & operator<<(ostream & x,PS & y); PS operator*(PS y);
z.T=T-y.T; z.A=A-y.A; return z; } void main() { SP x,y,z; cout<<"SP x: \n";cin>>x; cout<>y; cout<>) và xu ất (<<): nh ậ p các giá tr ị m, n và ma tr ận a. Xuất ma tr ận: xuất các giá tr ị của ma tr ận a lên màn hình. Phươ ng thức toán tử “Đổi dấu ma tr ận” (-): đổi dấu tất cả các phần tử của ma tr ận. Xây dựng chươ ng trình chính trong đó khai báo một đối tượ ng thuộc lớ p ma tr ận. Nhậ p các giá tr ị cho ma tr ận, đổi dấu ma tr ận và in ma tr ận đã đổi dấu ra màn hình. #include #include #include #include class MT { int n,m; float a[100][100]; public: friend istream & operator>>(istream & x,MT & y); friend ostream & operator<<(ostream & x,MT & y); MT operator-(); }; istream & operator>>(istream & x,MT & y) { cout<<"n= ";x>>y.n;
cout<<"m= ";x>>y.m; for(int i=0;i>y.a[i][j]; } return x; } ostream & operator<<(ostream & x,MT & y) { for(int i=0;i>y; z=-y; cout<<"Doi dau: \n"<>) và xuất (<<) ma tr ận. Xây dựng chươ ng trình chính minh hoạ cách sử dụng các phươ ng thức toán tử trên. #include CN: Tr ần Xuân Thứ c
for(int i=0;i>y; z=-y; cout<<"Ma tran chuyen vi: \n"<
Bài 4.6. Xây dựng lớ p Tam thức bậc hai vớ i các thuộc tính là các h ệ số a, b, c th ực và các phươ ng thức: Phươ ng thức khở i tạo: khở i gán các giá tr ị của các hệ số a, b, c. 2
Phươ ng thức xuất: in tam th ức lên màn hình (có d ạng ax +bx+c = 0) Phươ ng thức toán tử “Đổi dấu tam thức”: toán tử cộng hai tam thức theo định ngh ĩ a : 2
2
đổi dấu các hệ số a, b, c. Xây dựng 2
(a1x +b1x+c1=0 ) + (a2x +b2+c2=0) = (a1+a2)x +(b1+b2)x+(c1+c2)=0. Xây dựng chươ ng trình chính khai báo một đối t ượ ng thuộc l ớ p Tam thức. Khở i gán giá tr ị cho các hệ số, đảo dấu các hệ số và in tam th ức đã đảo dấu ra màn hình. #include #include #include class TT { float a,b,c; public: friend istream & operator>>(istream & x,TT & y); friend ostream & operator<<(ostream & x,TT & y); TT operator+(TT y);
cout<>y; cout<
Bài 4.7. Cài đặt mảng một chiều gồm các phươ ng thức nhậ p (), xuất () và các toán tử: Sắ p mảng tăng dần (++); Sắ p mảng giảm dần (- -); #include #include #include class Mang { int n; float a[100]; public: void nhap(); void xuat(); Mang operator++(); Mang operator--(); }; void Mang::nhap() { cout<<"n= ";cin>>n; for(int i=0;i
CN: Tr ần Xuân Thứ c
for(i=0;i
Bài 4.8. Xây dựng các lớ p thờ i gian (TIME) để lưu tr ữ thờ i gian gồm: Giờ , phút, giây. Thực hiện cài đặt toán tử nhậ p (>>), xu ất (<<) và các phép toán t ử +, ++, < VD: TIME A(1,59,59), B, C; Cin>>B //nhậ p: 1, 59, 6 C=A+B; Cout< #include #include CN: Tr ần Xuân Thứ c
if(p==60) { p=0; g=g+1; } } int Time::operator<(Time y) { if(gy.g) return 0; else if(py.p) return 0; else if(gi>B; C=A+B; cout<
V. PHƯƠ NG THỨ C ẢO VÀ LIÊN K ẾT ĐỘNG . 1. Con trỏ đối tượ ng và các ph ươ ng thứ c t ĩ nh Giả sử có 3 lớ p A, B, C k ế thừa nhau theo cây thứ bậc sau: A
B
C
Tức lớ p B k ế thừa lớ p A, L ớ p C lại k ế thừa tr ực tiế p lớ p B. Nếu ta khai báo một con tr ỏ đối tượ ng P thuộc lớ p A (A * P) thì: P có th ể chứa địa chỉ của các đối tượ ng thuộc lớ p A hoặc B hoặc C. VD: Ta khai báo: A a, *P; B b; C c; thì ta có th ể viết: P = &a; ho ặc P = & b; ho ặc P = & c; Xét tr ườ ng hợ p cả 3 lớ p A, B, C đều có cùng một phươ ng thức: cùng tên, cùng danh sách các
đối, chỉ khác nhau về nội dung phươ ng thức. Khi đó, n ếu ta viết: P
; thì phươ ng thức nào trong 3 phươ ng thức của 3 lớ p sẽ đượ c gọi? p A sẽ đượ c g ọi, cho dù P có tr ỏ tớ i đối Câu tr ả l ờ i là: Chỉ có phươ ng thức c ủa l ớ tượ ng thuộc lớ p B và C. VD: Xét đoạn trình mô tả 3 l ớ p A, B, C k ế thừa nhau theo cây th ứ bậc trên. Cả 3 lớ p đều có phươ ng thức giống nhau là phươ ng thức nhap(). class A { int a; public:
void nhap() { cout<<"Nhap a "; cin>>a; } };
class B: public A { int b; public:
void nhap() { cout<<" Nhap b "; cin>>b; } };
class C: public B { int c; public:
void nhap() { cout<<" Nhap c "; cin>>c; } }; Tại hàm main(), ta khai báo 3
đối tượ ng thuộc 3 lớ p A, B, C và m ột con tr ỏ p thuộc lớ p A. Khi đó, mặc dù p tr ỏ tớ i đối tượ ng của lớ p B, C nh ững khi viết p nhap() thì phươ ng thức nhap() của lớ p A v ẫn đượ c gọi. void main() { A d1, *p; B d2; C d3;
p = & d2; p->nhap();//van la phuong thuc nhap() cua lop A p = & d3; p->nhap();//van la phuong thuc nhap() cua lop A }
2. Phươ ng thứ c ảo và ý ngh ĩ a của phươ ng thứ c ảo Trong nhiều tr ườ ng hợ p, ta mong mu ốn: Khi con tr ỏ đối tượ ng p thuộc lớ p A đang chứa địa chỉ của một đối tượ ng thuộc lớ p B hoặc C mà ta vi ết: P nhap(); thì sẽ truy cậ p t ớ i phươ ng thức nhap() của lớ p B hoặc C. Muốn đượ c như vậy thì ph ươ ng thức nhap() của 3 lớ p A, B, C phải là phươ ng thức ảo. Các phươ ng thức viết theo kiểu thông thườ ng đều là các ph ươ ng thức t ĩ nh. Phươ ng thức nhap() trong ví dụ trên là phươ ng thức t ĩ nh. Cách chuyển phươ ng thức t ĩ nh thành phươ ng thức ảo: Cách 1: Thêm từ khoá virtual vào tr ướ c phươ ng thức t ĩ nh của cả tất cả các lớ p (cơ sở và dẫn xuất). VD: Đoạn trình sau chuyển phươ ng thức t ĩ nh nhap() thành phươ ng thức ảo: class A { int a; public:
virtual void nhap() { cout<<"Nhap a "; cin>>a; } };
C d3; p = & d2; p->nhap();//phuong thuc nhap() cua lop B duoc goi p = & d3; p->nhap();//phuong thuc nhap() cua lop C duoc goi }
3. Phươ ng thứ c ảo và sự k ết nối động Trong ví dụ trên, cùng một lờ i gọi phươ ng thức : p nhap(); nhưng có thể truy cậ p tớ i phươ ng thức ảo của lớ p A hoặc B hoặc C. Lờ i gọi p nhap(); tươ ng ứng vớ i 3 phươ ng thức nhap() khác nhau. Khi ta sử dụng phươ ng thức ảo, rõ ràng là: cùng một con tr ỏ thuộc lớ p cơ sở , cùng một lờ i gọi phươ ng thức nhưng lờ i g ọi đó lại tươ ng ứng vớ i nhiều phươ ng thức khác nhau. Ta gọi đó là sự tươ ng ứng bội hay tính đa hình. Lờ i g ọi p nhap(); có thể k ết n ối t ớ i ph ươ ng thức nhap() của l ớ p A hoặc l ớ p B, hoặc lớ p C. Điều đó có ngh ĩ a là lờ i gọi đó không liên k ết cứng tớ i một phươ ng thức nhap() nào mà sự liên k ết đó là động. Như vậy, khi sử dụng phươ ng thức ảo thì ta có th ể liên k ết động từ một lờ i gọi phươ ng thức tớ i nhiều phươ ng thức cùng tên, cùng bộ đối số. Tính chất như vậy của phươ ng thức ảo gọi là sự k ết nối động. 4. Ví dụ về sử dụng phươ ng thứ c ảo Xây dựng lớ p Cây gồm các thu ộc tính: Chi ều cao, độ tuổi, chu vi tán và các phươ ng thức: Phươ ng thức nhậ p: nhậ p các giá tr ị cho các thuộc tính của lớ p Cây. Phươ ng thức xu ất: xuất các giá tr ị của các thuộc tính thuộc lớ p Cây lên màn hình. Xây dựng lớ p Cây cảnh, ngoài các thu ộc tính của lớ p Cây còn có các thuộc tính: Giá thành, chủng loại và các phươ ng thức: Phươ ng thức nhậ p: nhậ p các giá tr ị cho các thuộc tính của lớ p Cây cảnh. p Cây cảnh lên Phươ ng thức xu ất: xuất các giá tr ị của các thuộc tính thuộc l ớ màn hình. Viết chươ ng trình chính khai báo 2 đối tượ ng thuộc 2 lớ p trên và m ột con tr ỏ thuộc lớ p Cây. Dùng con tr ỏ này để nhậ p, xuất các thuộc tính của hai đối tượ ng trên.
5. Lớ p cơ sở trừ u tượ ng và các thành ph ần ảo Trong nhiều tr ườ ng hợ p, ta chỉ muốn dùng con tr ỏ của lớ p cơ sở để truy cậ p tớ i các phươ ng thức ảo của các lớ p dẫn xuất. Ngoài ra, r ất ít khi dùng con tr ỏ lớ p cơ sở để truy cậ p tớ i phươ ng thức ảo của chính lớ p này. Tuy nhiên, để con tr ỏ của lớ p cơ sở có thể truy cậ p các ph ươ ng thức ảo của các lớ p dẫn xuất thì l ớ p cơ sở cũng phải có phươ ng thức ảo này. Từ đây xuất hiện một khả năng: Phươ ng thức ảo của lớ p cơ sở có thể chỉ đượ c định ngh ĩ a hình thức mà không đượ c dùng. Khi đó thân của phươ ng thức ảo này không cần có bất cứ dòng lệnh nào. Một ph ươ ng thức ảo c ủa l ớ p cơ sở mà trong thân c ủa nó không thực thi một l ệnh nào (tr ừ return) gọi là phươ ng thức thuần ảo. Lớ p cơ sở có phươ ng thức thuần ảo gọi là lớ p cơ sở tr ừu tượ ng. Khi thiết k ế phần m ềm h ướ ng đối t ượ ng, ta luôn xác định đượ c các lớ p có thể có trong phần mềm và cây th ứ bậc thể hiện sự k ế thừa của các lớ p. Ngườ i ta thườ ng tạo ra các lớ p c ơ sở tr ừu tượ ng, trong đó có các phươ ng thức thuần ảo. Những phươ ng thức như vậy không thực hiện một công việc nào mà chỉ dùng để tạo phươ ng thức ảo cho các phươ ng thức cùng tên trong các l ớ p d ẫn xu ất. Từ đó, chỉ cần khai báo một con tr ỏ thuộc lớ p cơ sở tr ừu tượ ng này, ta có thể dùng con tr ỏ đó để truy cậ p tớ i các phươ ng thức ảo của các lớ p dẫn xuất. Từ đây, tạo ra sự linh hoạt trong truy cậ p các lớ p dẫn xuất. Phươ ng thức ảo chỉ đượ c t ạo ra sau khi đã hình thành đối t ượ ng, do vậy, phươ ng thức khở i tạo không thể là phươ ng thức ảo nhưng phươ ng thức huỷ bỏ có thể là phươ ng thức ảo. Ngoài ra, phươ ng thức toán tử cũng có thể là phươ ng thức ảo. Ư u nhượ c điểm của phươ ng thứ c ảo: Chươ ng trình sử dụng nhiều phươ ng thức ảo sẽ linh hoạt hơ n trong sự truy cậ p các phươ ng thức cùng tên của các l ớ p dẫn xuất. Việc thực thi chươ ng trình sẽ chậm hơ n. Tốn nhiều b ộ nhớ hơ n do phải t ạo ra một b ảng chỉ mục c ủa các phươ ng thức ảo. CN: Tr ần Xuân Thứ c
Khi nào dùng ph ươ ng thứ c ảo? Ta chỉ thiết k ế các lớ p có ph ươ ng thức ảo khi: Có sự k ế thừa giữa các lớ p. Các lớ p trong cây thứ bậc có các phươ ng thức cùng tên, cùng đối số, lớ p cơ sở ban đầu (lớ p gốc) bắt buộc cũng phải có phươ ng thức này. Bản chất của cây th ứ bậc đòi hỏi cần có phươ ng thức ảo. Bài 5.1. Xây dựng lớ p cơ sở Xe gồm thuộc tính năm sản xuất, tr ọng lượ ng và phươ ng thức tính giá thành: Giá thành = (n ăm sản xuất * 0.2 + tr ọng lượ ng), phươ ng thức khở i tạo khở i gán các giá tr ị cho các thuộc tính của lớ p Xe, phươ ng thức Xuất đưa các thông tin của xe và giá thành lên màn hình. Xây dựng l ớ p dẫn xuất Xe tải k ế thừa tất cả các thuộc tính và ph ươ ng thức trên của lớ p Xe, ngoài ra còn có thêm thu ộc tính Tr ọng tải và các phươ ng thức: Phươ ng thức khở i tạo: khở i gán các giá tr ị thuộc tính cho xe t ải. Phươ ng thức Tính giá thành: Giá thành = Tr ọng tải *200. Phươ ng thức xuất, đưa các thông tin và giá thành c ủa xe tải lên màn hình. Xây dựng chươ ng trình chính s ử dụng m ột con tr ỏ đối tượ ng thuộc l ớ p Xe. Sử dụng con tr ỏ này để nhậ p thông tin cho đối tượ ng thuộc lớ p Xe và in các thông tin vừa nhậ p lên màn hình kèm theo giá thành c ủa Xe. Vẫn s ử dụng con tr ỏ này để nhậ p thông tin cho đối tượ ng thuộc l ớ p Xe tải và in các thông tin v ừa nhậ p lên màn hình kèm theo giá thành c ủa Xe tải. #include #include #include #include class Xe { public: int NamSX; float TL; Xe(int x1,float x2) { NamSX=x1; TL=x2; } Xe() { NamSX=TL=0; } virtual void nhap() { cout<<"Nam san xuat: ";cin>>NamSX; cout<<"Trong luong: ";cin>>TL; } virtual void gt() { float GT=0; GT=(NamSX*0.2+TL); CN: Tr ần Xuân Thứ c