Chương 1- Giới thiệu về lập trình hướng đối tượng
Lập trình hướng đối tượng (Object Oriented Programming - OOP)
được xem là:
- Cách tiếp cận mới, hiệu quả hơn
- Giúp tăng năng suất
- Dễ dàng bảo trì, sửa đổi, nâng cấp
Mục đích của lập trình hướng đối tượng:
- Giảm bớt thao tác viết trình
- Mô tả chân thực thế giới thực
              
                                            
                                
            
 
            
                 163 trang
163 trang | 
Chia sẻ: phuongt97 | Lượt xem: 644 | Lượt tải: 0 
              
            Bạn đang xem trước 20 trang nội dung tài liệu Bài giảng Kỹ thuật lập trình hướng đối tượng với C++ - Hoàng Kim Bảng, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
c
b = a; // lỗi: Cannot convert ‘Phanso1’ to ‘Phanso2’
 Khi gán, các thành phần thừa (không có trong lớp cha) sẽ bị 
 cắt tỉa và chuyển đổi kiểu lên an toàn.
5.4. Định nghĩa lại quyền truy xuất
 Để định nghĩa lại chỉ cần liệt kê thành phần đó sau từ khoá 
 quyền truy xuất tương ứng
: ::;
 Ví dụ: class A
{ private: f1, f2 ;
 protected: f3, f4 ;
 public: f5, f6 ;
};
 class B : A
{ public: 
 A::f6 ;
};
 Kết quả: f1, f2, f3, f4, f5 là private, còn f6 là public
Chú ý:
- Khi định nghĩa lại quyền truy xuất với 1 thành phần thì mọi 
 thành phần cùng tên cũng bị tác động
- Chỉ có thể định lại quyền truy xuất theo đúng quyền của thành 
 phần đó trong lớp cha
- Nếu trong lớp cơ sở có nhiều thành phần cùng tên nhưng khác 
 quyền truy xuất thì không thể định nghĩa lại
- Nếu lớp con có một thành phần cùng tên thì thành phần của 
 lớp con sẽ che phủ thành phần lớp cha, muốn truy xuất phải 
 viết tường minh
5.5. Hàm khởi tạo và hàm huỷ
a. Hàm khởi tạo
- Hàm khởi tạo của lớp cha không được kế thừa
- Mỗi đối tượng của lớp con có thể coi là một đối tượng của lớp 
 cha. Do đó: khi gọi hàm khởi tạo của lớp con sẽ kéo theo gọi 
 hàm khởi tạo của lớp cha
 Thứ tự gọi:
 Hàm khởi tạo lớp cha  Hàm khởi tạo lớp con
- Nếu xây dựng hàm khởi tạo của lớp con: Phải gọi hàm khởi tạo 
 của lớp cha tường minh
Cú pháp:
([th/số]): ([th/số])
{ }
VD:
class sophuc
{ protected:
 double thuc, ao;
 public:
 sophuc()
 { thuc = 0; ao = 0; }
 ..
} ;
class sophuc1 : public sophuc
{ public:
 sophuc1() : sophuc() { };
..
} ;
Chú ý:
- Hàm khởi tạo lớp cơ sở thực hiện trước
- Nếu lớp dẫn xuất có nhiều lớp cơ sở thì trình tự thực hiện tuân 
 theo trình tự kế thừa.
 b. Hàm huỷ
- Hàm huỷ của lớp cơ sở không được kế thừa
- Các hàm huỷ được thi hành theo trình tự ngược lại so với hàm 
 khởi tạo
- Hàm huỷ của lớp dẫn xuất thi hành trước hàm huỷ của lớp cơ 
 sở
5.6. Đa kế thừa
- Đa kế thừa là khả năng xây dựng lớp dẫn xuất kế thừa từ 
 nhiều hơn một lớp cơ sở
- Đa kế thừa có thể là tính năng rất mạnh nhưng đôi khi gây ra 
 một số vấn đề.
VD:
 A B
 C
Khai b¸o líp C nh sau:
class C: public A, public B
{
};
 Bªn trong líp C cã thÓ khai b¸o c¸c thµnh phÇn d÷ liÖu 
 vµ c¸c ph¬ng thøc cña líp C.
Thø tù gäi c¸c hµm t¹o nh sau: 
C¸c hµm t¹o cña c¸c líp c¬ së theo thø tù khai b¸o cña c¸c 
 líp c¬ së trong líp dÉn xuÊt ®îc gäi tríc vµ sau cïng lµ 
 hµm t¹o cña líp dÉn xuÊt míi ®îc gäi. 
Nh vÝ dô trªn, hµm t¹o cña líp A ®îc gäi tríc, sau ®ã lµ hµm 
 t¹o cña líp B vµ cuèi cïng lµ hµm t¹o cña líp C ®îc gäi.
Thø tù gäi c¸c hµm hñy nh sau: 
C¸c hµm hñy ®îc gäi theo thø tù ngîc l¹i víi c¸ch gäi c¸c 
 hµm t¹o.
Trong vÝ dô trªn, hµm hñy cña líp C sÏ ®îc gäi ®Çu tiªn råi 
 ®Õn hµm hñy cña líp B ®îc gäi vµ cuèi cïng lµ hµm hñy 
 cña líp A ®îc gäi.
C¸c thuéc tÝnh thõa kÕ: 
§a thõa kÕ còng cã tÝnh chÊt thõa kÕ nh kiÓu thõa kÕ 
 ®¬n.
C¸ch gäi c¸c hµm thµnh phÇn cña c¸c líp c¬ së:
VÝ dô: Líp C thõa kÕ tõ líp A vµ tõ líp B.
 NÕu líp A cã hµm hienthi( ), líp B cã hµm hienthi( ), th×
 ë líp C ta sö dông hµm hienthi ( ) cña líp nµo th× ph¶i 
 chØ râ ph¹m vi hµm ®ã :
void C:: hienthi( )
{
 .....
 A::hienthi( ); // sö dông hµm thµnh phÇn cña líp c¬ së A
 .....
 B::hienthi( ); // sö dông hµm thµnh phÇn cña líp c¬ së B
 .....
}
VD: X©y dùng líp diem_mau kÕ thõa líp diem vµ líp mau :
 diem mau
 int x, y; int mau;
 diem_mau
#include 
#include 
class diem
{ private: 
 int x, y;
 public:
 diem()
 { x=0; y=0; }
 diem(int xd, int yd )
 { x=xd; y=yd; }
 void hienthi()
 { cout<<"\nDiem ("<<x<<", "<<y<<“)”; }
};
class mau
{ int m;
 public:
 mau()
 { m = 0; }
 mau (int md)
 { m = md; }
 void hienthi()
 { cout<<"\nMau :"<< m; }
};
class diem_mau : public diem, public mau
{ public :
 diem_mau() : diem(), mau() { } ;
 diem_mau ( int xd, int yd, int md ): 
 diem(xd, yd), mau(md)
 { }
 void hienthi()
 {
 diem :: hienthi();
 mau :: hienthi();
 }
};
void main()
{
 diem_mau A(3,4,5);
 cout<<"\nGoi phuong thuc hienthi() cua lop diem_mau:";
 A.hienthi();
 cout<<"\nGoi phuong thuc hienthi() cua lop diem:";
 A.diem::hienthi();
 cout<<"\nGoi phuong thuc hienthi() cua lop mau:";
 A.mau::hienthi();
 getch();
}
Bài tập chương 5
1/ Xây dựng lớp sophuc gồm phần thực, phần ảo, phương thức: 
 nhập, in.
Xây dựng lớp sophuc1 kế thừa lớp sophuc, bổ sung các phép +, -
Hàm main: Nhập 2 số phức Y, Z. Tính và in Y + Z, Y – Z.
2/ Xây dựng lớp thí sinh TS gồm: SBD, ngày sinh, khu vực, 
 nhập, in.
Xây dựng lớp thí sinh khối A là TSA kế thừa lớp TS, bổ sung: 
 điểm toán, lý, hoá, hoàn thiện phương thức nhập, in.
Hàm main:
 Nhập danh sách thí sinh khối A, in danh sách thí sinh trúng 
 tuyển với tổng điểm >= 15.
3/ Cài đặt lớp PS1 gồm có:
 Dữ liệu: tử số, mẫu số
 Phương thức: nhập phân số (mẫu khác 0), in phân số, tối 
 giản.
Cài đặt lớp PS2 kế thừa PS1 và bổ sung:
 Phương thức: toán tử >>, <<, phép +, -, *, /, phép so sánh: 
 ==, !=, >, >=, <, <=, ++, --
 Chương trình chính: nhập 2 phân số, thông báo các kết quả 
 tính toán và so sánh.
4/ Cài đặt lớp người NGUOI gồm có:
 – Dữ liệu: họ tên, mã số, lương
 – Phương thức: nhập, in
Cài đặt lớp người trong biên chế BC kế thừa lớp NGUOI và bổ 
 sung:
 Dữ liệu: hệ số lương, phụ cấp
 Phương thức: định nghĩa lại phương thức nhập và tính 
 lương.
Cài đặt lớp người làm hợp đồng HD kế thừa lớp NGUOI và bổ 
 sung:
 Dữ liệu: tiền công lao động, số ngày làm việc trong tháng, hệ 
 số vượt giờ.
 Phương thức: định nghĩa lại phương thức nhập và tính 
 lương.
Chương trình chính: nhập mảng các n người (n < 100), in ra 
 danh sách này.
Chương 6 – Tính đa hình
6.1. Khái niệm kết gán sớm và kết gán muộn
- Kết gán kiểu sớm (tức là hàm thành phần gọi từ con trỏ đối 
 tượng được xác định ngay khi khai báo – lúc biên dịch 
 chương trình).
- Kết gán kiểu muộn (lúc chạy chương trình), nghĩa là xác định 
 hàm thành phần nào tương ứng với một lời gọi hàm thành 
 phần từ con trỏ đối tượng phụ thuộc cụ thể vào đối tượng mà 
 con trỏ đang chứa địa chỉ.
 Khái niệm hàm ảo được đưa ra nhằm đáp ứng nhu cầu này.
Ví dụ: Xây dựng lớp B và lớp C cùng kế thừa từ lớp A.
#include 
 class A
#include 
class A
 class B class C
{ public:
 void hienthi( ) { cout<<"Lop co so A“<<endl; }
};
class B : public A
{ public:
 void hienthi( ) { cout<<"Lop dan xuat B“<<endl; }
};
class C : public A
{ public:
 void hienthi( ) { cout<<"Lop dan xuat C<<endl}
};
void main()
{ A *p;
 p -> hienthi();
 B b; 
 p = &b;
 p -> hienthi();
 C c;
 p = &c;
 p -> hienthi();
 getch();
}
Kết quả đều hiển thị ra: Lop co so A
Ph¶i sö dông hµm ¶o ®Ó ®îc kÕt qu¶ mong muèn.
6.2. Hàm ảo
Cú pháp :
virtual ([các tham số]) {  }
 - Hàm ảo là hàm thành phần của lớp
 - Được khai báo trong lớp cơ sở và định nghĩa lại trong lớp 
 dẫn xuất.
 - Hàm ảo sẽ được gọi thực hiện từ đối tượng của lớp dẫn 
 xuất.
VD:
#include 
#include 
class A
{ public:
 virtual void hienthi() { cout<<"Lop co so A"; }
};
class B : public A
{ public:
 void hienthi() { cout<<"Lop dan xuat B"; }
};
class C : public A
{ public:
 void hienthi() { cout<<"Lop dan xuat C"; }
};
void main()
{ clrscr();
 A a, *p;
 p = &a; p->hienthi(); cout<<"\n";
 B b;
 p = &b; p -> hienthi(); cout<<"\n";
 C c;
 p = &c; p -> hienthi();
 getch();
}
Kết quả:
Lop co so A
Lop dan xuat B
Lop dan xuat C
Một số chú ý:
 - Định nghĩa các hàm ảo giống như các hàm thông thường
 - Sử dụng con trỏ để truy cập tới hàm ảo
 - Định nghĩa trong lớp cơ sở ngay cả khi nó không được sử 
 dụng
 - Không có hàm khởi tạo ảo, nhưng có thể có hàm huỷ ảo
 - Con trỏ của lớp cơ sở có thể chứa địa chỉ của đối tượng lớp 
 dẫn xuất
6.3. Lớp cơ sở ảo
 Xét ví dụ: A là lớp cơ sở của lớp B và lớp C, D là lớp dẫn 
 xuất của lớp B và lớp C.
Có sự nhập nhằng trong đa kế thừa.
 class A
class A { public: int i; };
class B : public A { }; class B class C
class C : public A { };
class D : public B, public C { ... }; class D
...
D d;
d.i = 0; //Nhập nhằng: Member is ambiguous: 'A::i' and 'A::i'
#include 
class A
{ public:
 int i;
};
class B : public A
{ public:
 float f;
};
class C : public A
{ public:
 double d;
};
class D : public B , public C
{ public:
 char c;
};
void main()
{ D d;
 d.i = 0; //Nhập nhằng: Member is ambiguous: 'A::i' and 'A::i'
 d.f = 3.141593; d.d = 1.5; d.c = 'a';
 cout<<"i = "<<d.i<<endl; //Nhập nhằng: Member is ambiguous
 cout<<"f = "<<d.f<<endl;
 cout<<"d = "<<d.d<<endl;
 cout<<"c = "<<d.c;
}
Giải quyết:
 Coi A là lớp cơ sở ảo của cả B và C. Khi đó trong D chỉ có 
 một sự thể hiện của A
Khai báo:
 class : virtual 
 VD:
class B: virtual public A {  } ;
class C: virtual public A {  } ;
#include 
#include 
class A
{ public:
 int i;
};
class B : virtual public A
{ public:
 float f;
};
class C : virtual public A
{ public:
 double d;
};
class D : public B, public C
{ public:
 char c;
};
void main()
{ D d;
 d.i = 0; d.f = 3.141593; d.d = 1.5; d.c = 'a‘;
 cout<<"i = "<< d.i<<endl;
 cout<<"f = "<<d.f<<endl;
 cout<<"d = "<<d.d<<endl;
 cout<<"c = "<<d.c;
 getch();
}
6.4. Lớp trừu tượng và hàm ảo thuần tuý
Mục đích:
 - Tránh lãng phí bộ nhớ
 - Cung cấp một phương thức thống nhất làm giao diện chung.
Khai báo hàm ảo thuần túy:
virtual ([các tham số])=0;
Đặc điểm:
 - Không bắt buộc định nghĩa trong lớp cơ sở
 - Không thể khai báo đối tượng thuộc lớp có hàm ảo thuần tuý
 - Lớp có hàm ảo thuần tuý và chỉ làm lớp cơ sở cho lớp khác
 gọi là lớp cơ sở trừu tượng
 - Lớp dẫn xuất kế thừa lớp cơ sở trừu tượng mà không định 
 nghĩa lại phương thức ảo thuần tuý  nó trở thành lớp cơ sở 
 trừu tượng 
#include 
#include 
#define PI 3.141593
class Hinh
{ public:
 virtual float Dien_tich() = 0; // Hµm ¶o thuÇn tóy
};
class Tron : public Hinh
{ float r;
 public:
 Tron(float rr=0) { r = rr; }
 float Dien_tich() { return PI*r*r; } //Định nghĩa lại
};
class Chu_nhat: public Hinh
{ float dai, rong;
 public:
 Chu_nhat(float d = 0, float r = 0)
 { dai = d; rong = r; }
 float Dien_tich() { return dai*rong;} //Định nghĩa lại
};
void main()
{
 Hinh *hinh;
 Tron tron(5); //Khai bao hinh tron ban kinh 5
 Chu_nhat ch_nhat(4,3); //Kh/bao chu nhat voi kich thuoc 4 va 3
 hinh = &tron; 
 cout Dien_tich() << endl;
 hinh = &ch_nhat; 
 cout Dien_tich() << endl;
 getch();
}
Bài tập chương 6
1/ Cài đặt lớp người Nguoi gồm có:Dữ liệu: họ tên, phương thức 
 nhập, phương thức ảo in ra, phương thức ảo được khen 
 thưởng
Cài đặt lớp sinh viên SinhVien kế thừa lớp Nguoi và bổ sung:
Dữ liệu: điểm trung bình, phương thức: định nghĩa lại phương 
 thức nhập, phương thức ảo in, phương thức ảo được khen 
 thưởng nếu điểm trung bình từ 9 trở lên
Cài đặt lớp giảng viên GiangVien kế thừa lớp Nguoi và bổ sung:
Dữ liệu: số bài báo, phương thức: định nghĩa lại phương thức 
 nhập, phương thức ảo in, phương thức ảo được khen thưởng 
 nếu có số bài báo từ 5 trở lên
Chương trình chính: nhập mảng các n người (n < 100), in ra 
 danh sách này.
2/ Cài đặt lớp người NGUOI gồm có:
 Dữ liệu: họ tên, mã số, lương
 Phương thức ảo nhập, in, ảo tính lương
Cài đặt lớp người trong biên chế BC kế thừa lớp NGUOI và bổ 
 sung: Dữ liệu: hệ số lương, phụ cấp; Phương thức: định nghĩa 
 lại phương thức nhập và tính lương.
Cài đặt lớp người làm hợp đồng HD kế thừa lớp NGUOI và bổ 
 sung:Dữ liệu: tiền công lao động, số ngày làm việc trong 
 tháng, hệ số vượt giờ; Phương thức: định nghĩa lại phương 
 thức nhập và tính lương.
Chương trình chính: nhập mảng các n người (n < 100), in ra 
 danh sách này.
Chương 7 – Khuôn hình 
 (template)
7.1. Khuôn hình hàm
7.1.1. Khuôn hình hàm là gì ?
 Khuôn hình hàm cho phép sử dụng cùng một tên hàm duy 
 nhất để thực hiện các công việc khác nhau. So với định nghĩa 
 chồng hàm, khuôn hình hàm mạnh hơn rất nhiều vì chỉ cần 
 viết định nghĩa khuôn hình hàm một lần, rồi sau đó chương 
 trình dịch làm cho nó thích ứng với các kiểu dữ liệu khác 
 nhau.
7.1.2. Tạo một khuôn hình hàm
Ví dụ xây dựng hàm tìm max của hai số bất kỳ:
int max(int a, int b)
 { if(a > b) return a;
 else return b;}
float max(float a, float b)
 { if(a>b) return a;
 else return b;}
Có thể tiếp tục tạo ra rất nhiều định nghĩa hàm hoàn toàn tương 
 tự nhau, chỉ có kiểu dữ liệu các tham số, kiểu trả về là thay 
 đổi.
C++ cho phép giải quyết vấn đề trên bằng cách định nghĩa một 
 khuôn hình hàm duy nhất như sau:
template 
T max ( T a, T b)
 { if(a>b) return a ;
 else return b;}
So với định nghĩa hàm thông thường, chỉ có dòng đầu tiên bị 
 thay đổi:
 template 
 T max ( T a, T b)
Trong đó:
 template xác định rằng đó là một khuôn hình với 
 một tham số kiểu T.
 T max ( T a, T b) nói rằng max ( ) là một hàm với hai tham số 
 hình thức kiểu T và có giá trị trả về kiểu T.
- Định nghĩa khuôn hình hàm:
template 
 ([ds tham số])
{
 //thân khuôn hình hàm
}
- Gọi hàm từ khuôn hình hàm:
(đối số)
Trong đó trùng tên khuôn hình hàm
Ví dụ:
int a, b ; float x, y ;
max(a,b) ;
max(x, y);
Chương trình như sau:
#include 
template 
T max ( T a, T b)
 { if(a>b) return a;
 else return b;}
main()
{
int a = 5, b = 3;
float x =2.5, y= 6.5;
cout << "max("<<a<<","<<b<<") = " << max(a,b);
cout << "\nmax("<<x<<","<<y<<") = " << max(x,y);
}
7.2. Khuôn hình lớp
7.2.1. Khuôn hình lớp là gì?
 Cũng giống như khuôn hình hàm, chỉ cần định nghĩa khuôn 
 hình lớp một lần rồi sau đó có thể áp dụng chúng với các kiểu 
 dữ liệu khác nhau để được các thể hiện lớp khác nhau.
7.2.2. Tạo một khuôn hình lớp
Ví dụ xây dựng lớp diem: 
class diem 
{ float x , y;
 public:
 diem (float xd = 0, float yd = 0);
 void hienthi ( );
}
 Nếu muốn tọa độ điểm có kiểu dữ liệu khác (int, long, 
 double) thì phải định nghĩa một lớp khác bằng cách thay 
 float bằng từ khóa tương ứng với kiểu dữ liệu mong muốn.
 C++ cho phép định nghĩa một khuôn hình lớp và sau đó áp 
 dụng khuôn hình lớp này với các kiểu dữ liệu khác nhau để 
 thu được các lớp thể hiện như mong muốn:
template 
class diem 
{ T x , y;
 public:
 diem ( T xd = 0, T yd = 0);
 void hienthi ( );
};
Định nghĩa khuôn hình lớp:
template 
class 
{
};
Định nghĩa hàm thành phần: có hai cách:
- Định nghĩa bên trong khai báo của khuôn hình lớp: giống như 
 hàm thông thường.
 - Định nghĩa bên ngoài khai báo: phải “nhắc lại” các tham số 
 kiểu của khuôn hình lớp:
VD: template void diem::hienthi( )
 {  }
VD: 
template 
class diem 
{ T x, y;
 public:
 diem(T xd = 0, T yd = 0)
 { x = xd ; y = yd; }
 void hienthi();
};
// Định nghĩa hàm thành phần ở bên ngoài khuôn hình lớp
template void diem::hienthi()
{ cout<<“Diem (“<< x << “ , “ << y << “)\n”; }
Sử dụng khuôn hình lớp :
 Mỗi giá trị của tham số kiểu, chương trình dịch sẽ phát sinh 
 ra một lớp cụ thể (gọi là lớp thể hiện của khuôn hình lớp).
 Khai báo đối tựơng lớp: 
Ví dụ:
diem a;
diem b;
diem c;
Ba dòng trên khai báo đối tượng a có hai thành phần tọa độ kiểu 
 int, đối tượng b có hai thành phần tọa độ kiểu float, đối tượng 
 c có hai thành phần tọa độ kiểu long.
Còn diem , hoặc diem , hoặc diem là các lớp 
 thể hiện của khuôn hình lớp diem.
Chương trình như sau:
#include 
template 
class diem 
{ T x , y;
 public:
 diem ( T xd = 0, T yd = 0) { x = xd ; y = yd; }
 void hienthi ( );
};
template void diem::hienthi( )
{ cout<<"Diem ("<< x << " , " << y << ")\n"; }
main ( )
{diem a(5, 3); diem b(2.5, 6.5);
 a.hienthi(); b.hienthi(); }
Bài tập chương 7
1/ Xây dựng hàm template tính tổng của một dãy các đối tượng 
 của lớp, sau đó áp dụng tính tổng một dãy số nguyên, một dãy 
 phân số. Chú ý xây dựng lớp phân số có hàm chồng toán tử +.
2/ Xây dựng hàm template sắp xếp tăng dần một dãy các đối 
 tượng của lớp, sau đó áp dụng sắp tăng dần một dãy số 
 nguyên, một dãy phân số. Chú ý xây dựng lớp phân số có hàm 
 chồng toán tử so sánh > 
3/ Xây dựng lớp template ngăn xếp stack . Áp dụng để khai báo 
 một stack chứa các số nguyên và sử dụng stack này để đổi số 
 từ hệ đếm 10 sang hệ đếm 2, hoặc hệ 8, hoặc hệ 16. Áp dụng 
 lớp template stack để khai báo một stack chứa các ký tự, ứng 
 dụng giải bài toán so khớp các dấu ngoặc đơn.
            Các file đính kèm theo tài liệu này:
 bai_giang_ky_thuat_lap_trinh_huong_doi_tuong_voi_c_hoang_kim.pdf bai_giang_ky_thuat_lap_trinh_huong_doi_tuong_voi_c_hoang_kim.pdf