[ C++ ] Tính đa hình, phương thức ảo, lớp trừu tượng trong C++ [Lập trình hướng đối tượng với C++]
* TÍNH ĐA HÌNH (Polymorphism)
Phương thức của lớp cha khi thực hiện sẽ được thay thế bằng một phương thức của lớp con thì phương thức này gọi là có tính đa hình. Tính đa hình giúp cho việc lập trình đơn giản và dễ mở rộng. Để cài đặt phương thức có tính đa hình ta dùng phương thức ảo và phương thức thuần ảo.
* PHƯƠNG THỨC ẢO (virtual method)
Phương thức ảo là phương thức được định nghĩa ở lớp cơ sở (lớp cha) mà các lớp dẫn xuất (lớp con) muốn sử dụng phải định nghĩa lại. Dùng từ khoá virtual để khai báo phương thức ảo:
Cú pháp:
virtual <kiểu trả về> <tên phương thức >(<d/s tham số>)
{
…
}
Phương thức khởi tạo không được là phương thức ảo nhưng phương thức hủy bỏ có thể là phương thức ảo. Dùng phương thức ảo chậm hơn phương thức thông thường vì khi thực hiện mới được xác định cụ thể.
Ví dụ [Code Tubor C++ 3.0/4.5]:
#include <iostream.h>
#include <conio.h>
class A
{
public:
virtual void Chao() //phuong thuc ao
{
cout<<"\nA chao cac ban";
}
};
// class B
class B:public A
{
public:
void Chao()
{
cout<<"\nB chao cac ban";
}
};
// class C
class C:public A
{
public:
void Chao()
{
cout<<"\nC chao cac ban";
}
};
// ham main
void main()
{
A a;
A *pa= new A; pa->Chao(); //goi chao cua A
B b;
pa=&b; pa->Chao(); //goi chao cua B
C c;
pa=&c; pa->Chao(); //goi chao cua C
getch();
}
Nhận xét:
- Phương thức Chao() có tính đa hình: cùng lời gọi pa->chao() nhưng lần 1 gọi chao cua A, lan 2 gọi chao cua B, lan 3 goi chao cua C.
- Nếu trong lớp B, C không định nghĩa lại phương thức chào thì cả ba lần đều gọi chào của A.
- Nếu phương thức chao() trong lớp A không khai báo virtual thì phương thức chao() sẽ không có tính đa hình, khi đó cả ba lần đều gọi chào của A.
- Có thể gán địa chỉ của đt thuộc lớp con vào biến con trỏ, trỏ tới đt thuộc lớp cha nhưng không thể làm ngược lại (áp dụng nguyên tắc “con gán vào cha” đối với biến kiểu đối tượng hoặc biến kiểu con trỏ, trỏ tới đối tượng)
* PHƯƠNG THỨC TRỪU TƯỢNG, LỚP TRỪU THƯỢNG
Phương thức trừu tượng (thuần ảo) là phương thức ảo nhưng không có lệnh (phương thức rỗng). Phương thức thuần ảo có dạng:
Cú pháp:
virtual <kiểu trả về> <tên phương thức >(<d/s tham số>) = 0;
Lớp có phương thức ảo gọi là lớp trừu tượng (abstract class). Nếu một lớp thừa kế lớp trừu tượng mà không định nghĩa lại phương thức thuần ảo thì lớp thừa kế cũng là lớp trừu tượng.
Lưu ý: không được tạo đối tượng thuộc lớp trừu tượng.
Thường ta chọn phương thức ở lớp cha, mà chưa thể xác định cách thực hiện, làm phương thức thuần ảo. Ở lớp con ta sẽ định nghĩa lại phương thức thuần ảo, để xác định cụ thể cách thức thực hiện.
Ví dụ:
Nhập một danh sách gồm giảng viên và sinh viên, in ra danh sách những người được thưởng. Biết rằng điều kiện được thưởng là giảng viên có số bài báo >3, sinh vien có điểm thi tốt nghiệp >8.
[Code Tubor C++ 3.0/4.5]
#include <iostream.h>
#include <conio.h>
class Nguoi
{
char hoten[30];
public:
virtual void nhap() //phuong thức ảo
{
cout<<"\nHo ten:"; cin.getline(hoten,30);
}
virtual int thuong()=0; //phuong thức thuần ảo
virtual void xuat() //phuong thức ảo
{
cout<<"\nHo ten:"<<hoten;
}
};
// class Sinhvien
class Sinhvien:public Nguoi
{
float dttn;
public:
void nhap() //dinh nghia l?i phuong th?c nh?p
{
Nguoi::nhap();
cout<<"\nDiem thi tn:"; cin>>dttn;
}
int thuong() //định nghĩa lại phương thức thưởng
{
return (dttn>8?1:0);
}
void xuat() //dinh nghia lại phuong thức xuất
{
cout<<"\n-Sinh vien:";
Nguoi::xuat();
cout<<"\nDiem thi tn:"<<dttn;
}
};
// class Giangvien
class Giangvien:public Nguoi
{
int sobaibao;
public:
void nhap()
{
Nguoi::nhap();
cout<<"\nSo bai bao:"; cin>>sobaibao;
}
int thuong()
{
return (sobaibao>3?1:0);
}
void xuat()
{
cout<<"\n-Giang vien:";
Nguoi::xuat();
cout<<"\nSo bai bao:"<<sobaibao;
}
};
// hàm main
void main()
{
Nguoi *ds[100]; int k=0, chon, i;
while(1)
{
cout<<"\n*Gv/Sv/Ngung (1,2,3):"; cin>>chon; cin.get();
if (chon==3) break;
if (chon==1) ds[k]=new Giangvien();
if (chon==2) ds[k]=new Sinhvien();
ds[k]->nhap(); k++;
}
cout<<"\n*Danh sach nhung nguoi duoc thuong";
for (i=0; i<k; i++)
if (ds[i]->thuong()) ds[i]->xuat();
getch();
}
{
A a;
A *pa= new A; pa->Chao(); //goi chao cua A
B b;
pa=&b; pa->Chao(); //goi chao cua B
C c;
pa=&c; pa->Chao(); //goi chao cua C
getch();
}
Nhận xét:
- Phương thức Chao() có tính đa hình: cùng lời gọi pa->chao() nhưng lần 1 gọi chao cua A, lan 2 gọi chao cua B, lan 3 goi chao cua C.
- Nếu trong lớp B, C không định nghĩa lại phương thức chào thì cả ba lần đều gọi chào của A.
- Nếu phương thức chao() trong lớp A không khai báo virtual thì phương thức chao() sẽ không có tính đa hình, khi đó cả ba lần đều gọi chào của A.
- Có thể gán địa chỉ của đt thuộc lớp con vào biến con trỏ, trỏ tới đt thuộc lớp cha nhưng không thể làm ngược lại (áp dụng nguyên tắc “con gán vào cha” đối với biến kiểu đối tượng hoặc biến kiểu con trỏ, trỏ tới đối tượng)
* PHƯƠNG THỨC TRỪU TƯỢNG, LỚP TRỪU THƯỢNG
Phương thức trừu tượng (thuần ảo) là phương thức ảo nhưng không có lệnh (phương thức rỗng). Phương thức thuần ảo có dạng:
Cú pháp:
virtual <kiểu trả về> <tên phương thức >(<d/s tham số>) = 0;
Lớp có phương thức ảo gọi là lớp trừu tượng (abstract class). Nếu một lớp thừa kế lớp trừu tượng mà không định nghĩa lại phương thức thuần ảo thì lớp thừa kế cũng là lớp trừu tượng.
Lưu ý: không được tạo đối tượng thuộc lớp trừu tượng.
Thường ta chọn phương thức ở lớp cha, mà chưa thể xác định cách thực hiện, làm phương thức thuần ảo. Ở lớp con ta sẽ định nghĩa lại phương thức thuần ảo, để xác định cụ thể cách thức thực hiện.
Ví dụ:
Nhập một danh sách gồm giảng viên và sinh viên, in ra danh sách những người được thưởng. Biết rằng điều kiện được thưởng là giảng viên có số bài báo >3, sinh vien có điểm thi tốt nghiệp >8.
[Code Tubor C++ 3.0/4.5]
#include <iostream.h>
#include <conio.h>
class Nguoi
{
char hoten[30];
public:
virtual void nhap() //phuong thức ảo
{
cout<<"\nHo ten:"; cin.getline(hoten,30);
}
virtual int thuong()=0; //phuong thức thuần ảo
virtual void xuat() //phuong thức ảo
{
cout<<"\nHo ten:"<<hoten;
}
};
// class Sinhvien
class Sinhvien:public Nguoi
{
float dttn;
public:
void nhap() //dinh nghia l?i phuong th?c nh?p
{
Nguoi::nhap();
cout<<"\nDiem thi tn:"; cin>>dttn;
}
int thuong() //định nghĩa lại phương thức thưởng
{
return (dttn>8?1:0);
}
void xuat() //dinh nghia lại phuong thức xuất
{
cout<<"\n-Sinh vien:";
Nguoi::xuat();
cout<<"\nDiem thi tn:"<<dttn;
}
};
// class Giangvien
class Giangvien:public Nguoi
{
int sobaibao;
public:
void nhap()
{
Nguoi::nhap();
cout<<"\nSo bai bao:"; cin>>sobaibao;
}
int thuong()
{
return (sobaibao>3?1:0);
}
void xuat()
{
cout<<"\n-Giang vien:";
Nguoi::xuat();
cout<<"\nSo bai bao:"<<sobaibao;
}
};
// hàm main
void main()
{
Nguoi *ds[100]; int k=0, chon, i;
while(1)
{
cout<<"\n*Gv/Sv/Ngung (1,2,3):"; cin>>chon; cin.get();
if (chon==3) break;
if (chon==1) ds[k]=new Giangvien();
if (chon==2) ds[k]=new Sinhvien();
ds[k]->nhap(); k++;
}
cout<<"\n*Danh sach nhung nguoi duoc thuong";
for (i=0; i<k; i++)
if (ds[i]->thuong()) ds[i]->xuat();
getch();
}
Hãy mở rộng bài tập trên bằng cách thêm một lớp nhân viên, biết rằng nhân viên có số ngày nghỉ trong năm < 5 là được thưởng.
Nhận xét:
Do phương thức “nhập, thưởng, xuất” là phương thức ảo của lớp người (lớp cha) nên các phương thức này khi thực thi sẽ có tính đa hình: có khi gọi “nhập, thưởng, xuất” của lớp giảng viên (lớp con), có khi thì gọi “nhập, thưởng, xuất” của lớp sinh viên (lớp con) tuỳ theo con trỏ ds[i] đang giữ địa chỉ của đối tượng giảng viên hay sinh viên.
Một số tài liệu và khoá học bổ ích dành cho bạn:
# Giáo Trình: Kỹ Thuật Lập Trình C/C++ Căn Bản Và Nâng Cao [Click để xem]
# Khoá học online: Học lập trình C/C++ TỪ A - Z [Click để xem]
* Có thể bạn quan tâm:
- Những cuốn sách mà các bạn không thể bỏ qua khi còn trẻ
- Khoá học tin học văn phòng tốt nhất
Chúc các bạn thành công!
----------