Tên lớp dẫn xuất: là tên lớp được cho thừa kế từ lớp khác. Tên lớp này tuân thđ theo quy tắc đặt tên biến trong C++.
Tên lớp cở sở: là tên lớp đã được định nghĩa trước đó để cho lớp khác thừa kế. Tên lớp này cũng tuân thđ theo quy tắc đặt tên biến cđa C++.
từ khóa dẫn xuất: là từ khóa quy định tính chất cđa sự thừa kế. Có ba từ khóa dẫn xuất là private, protected và public.
Ví dụ 3.1:
class Bus: public Car
{
…// Khai báo các thành phần
};
là khai báo một lớp Bus (xe buýt) thừa kế từ lớp Car (xe ô tô) với tính chất thừa kế là public.
Có thể bạn quan tâm!
- Hàm Tạo Và Đối Tượng Thành Phần
- Đối Tượng Hằng, Phương Thức Hằng
- Lập trình hướng đối tượng - 11
- Phạm Vi Truy Xuất Đến Các Thành Phần Cđa Lớp Cơ Sở
- Một Số Lớp Cơ Sở Xuất Hiện Nhiều Lần Trong Lớp Dẫn Xuất
- Lập trình hướng đối tượng - 15
Xem toàn bộ 256 trang tài liệu này.
3.1.3. Các kiểu thừa kế
Sự thừa kế cho phép trong lớp dẫn xuất có thể sử dụng lại một số mã nguồn cđa các phương thức và thuộc tính đã được định nghĩa trong lớp cơ sở. Nghĩa là lớp dẫn xuất có thể truy nhập trực tiếp đến một số thành phần cđa lớp cơ sở. Tuy nhiên, phạm vi truy nhập từ lớp dẫn xuất đến lớp cơ sở không phải bao giờ cũng giống nhau: chúng được quy định bởi các từ khóa dẫn xuất private, protected và public.
thừa kế private
Theo kiểu thừa kế này:
Các thành phần private cđa lớp cơ sở thì không thể truy nhập được từ lớp dẫn xuất.
Các thành phần protected cđa lớp cơ sở trở thành các thành phần private cđa lớp dẫn xuất.
Các thành phần public cđa lớp cơ sở cũng trở thành các thành phần private cđa lớp dẫn xuất.
Phạm vi truy nhập từ bên ngoài vào lớp dẫn xuất được tuân thđ như quy tắc phạm vi lớp thông thường.
thừa kế protected
Theo kiểu thừa kế này:
Các thành phần private cđa lớp cơ sở thì không thể truy nhập được từ lớp dẫn xuất.
Các thành phần protected cđa lớp cơ sở trở thành các thành phần protected cđa lớp dẫn xuất.
Các thành phần public cđa lớp cơ sở cũng trở thành các thành phần protected cđa lớp dẫn xuất.
Phạm vi truy nhập từ bên ngoài vào lớp dẫn xuất được tuân thđ như quy tắc phạm vi lớp thông thường.
thừa kế public
Theo kiểu thừa kế này:
Các thành phần private cđa lớp cơ sở thì không thể truy nhập được từ lớp dẫn xuất.
Các thành phần protected cđa lớp cơ sở trở thành các thành phần protected cđa lớp dẫn xuất.
Các thành phần public cđa lớp cơ sở vẫn là các thành phần public cđa lớp dẫn xuất.
Phạm vi truy nhập từ bên ngoài vào lớp dẫn xuất được tuân thđ như quy tắc phạm vi lớp thông thường.
3.1.4. thừa kế các thành phần dữ liệu
Các thuộc tính cđa lớp cơ sở được thừa kế trong lớp dẫn xuất. Như vậy, tập thuộc tính trong lớp dẫn xuất sẽ bao gồm: các thuộc tính mới khai báo trong lớp dẫn xuất và các thuộc tính mà lớp dẫn xuất được thừa kế từ các lớp cơ sở có liên quan. Tuy vậy, trong các phương thức cđa lớp dẫn xuất không được phép truy nhập vào các thuộc tính private cđa lớp cơ sở. Tên cđa thuộc tính trong lớp dẫn xuất và trong lớp cơ sở có thể đặt trùng nhau.
Ví dụ 3.2:
class Sinhvien
{
private:
char *MaSV; char *TenSV; char *Diachi; char *Gioitinh;
float DiemToanCC; float DiemVatly; float DiemAnhvan;
public:
void nhap(); void hienthi();
};
class SinhvienCNTT:Sinhvien
{
private:
float DiemLTC; float DiemCSDL;
public:
void nhap(); void hienthi();
int Xet_hocbong();
};
Khi đó lớp SinhvienCNTT ngoài các thuộc tính DiemLTC, DiemCSDL còn có các thuộc tính: MaSV, TenSV, Diachi, Gioitinh, DiemToanCC, DiemVatly, DiemAnhvan được thừa kế từ lớp Sinhvien.
3.1.5. thừa kế phương thức
Trũ: Hàm tạo, hàm huỷ và toán tử gán, các phương thức (public) khác cđa lớp cơ sở được thừa kế trong lớp dẫn xuất. Tên các phương thức cđa lớp dẫn xuất và lớp cơ sở có thể đặt trùng nhau.
Ví dụ 3.3:
#include<iostream.h>
#include<string.h>
#include<conio.h>
#include<iomanip.h>
#include<ctype.h>
#define MAX_TEN 50
#define MAX_MASO 5
#define MUC_CO_BAN 830000
class Nguoi
{
protected:
char HoTen[MAX_TEN]; char MaSo[MAX_MASO]; float Luong;
public:
Nguoi(); void Xuat(); void Nhap();
virtual void TinhLuong()=0;
};
Nguoi::Nguoi()
{
strcpy(HoTen,"");
strcpy(MaSo,""); Luong=0;
}
void Nguoi::Xuat()
{
cout<<"Ma so:"<<MaSo<<",Ho va ten:"<<HoTen; cout <<",Luong:"<<setiosflags(ios::fixed); cout<<setprecision(0)<<Luong<<endl;
}
void Nguoi::Nhap()
{
cout<<"Ma so:"; cin>>MaSo; cin.ignore(); cout<<"Ho va ten:";
cin.getline(HoTen,MAX_TEN);
}
class BienChe: public Nguoi
{
protected:
float HeSoLuong; float HeSoPhuCap;
public:
BienChe();
void TinhLuong(); void Nhap();
};
BienChe::BienChe()
{
HeSoLuong=HeSoPhuCap=0;
}
void BienChe::Nhap()
{
Nguoi::Nhap(); cout<<"He so luong:"; cin>>HeSoLuong;
cout<<"He so phu cap chu vu:"; cin>>HeSoPhuCap;
}
void BienChe::TinhLuong()
{
Luong=MUC_CO_BAN*(1.0+HeSoLuong+HeSoPhuCap);
}
class HopDong : public Nguoi
{
protected:
float TienCong; float NgayCong; float HeSoVuotGio;
public:
HopDong();
void TinhLuong(); void Nhap();
};
HopDong::HopDong()
{
TienCong=NgayCong=HeSoVuotGio=0;
}
void HopDong::Nhap()
{
Nguoi::Nhap(); cout<<"Tien cong:"; cin>>TienCong; cout<<"Ngay cong:"; cin>>NgayCong; cout<<"He so vuot gio:"; cin>>HeSoVuotGio;
}
void HopDong::TinhLuong()
{
Luong=TienCong*NgayCong*(1+HeSoVuotGio);
}
int main()
{
Nguoi *Ng[100]; int N=0;
char Chon,Loai; clrscr();
do
{
cout<<"Bien che hay Hop dong (B/H)? "; cin>>Loai;
Loai=toupper(Loai); if (Loai=='B')
Ng[N]=new BienChe; else
Ng[N]=new HopDong; Ng[N++]->Nhap();
cout<<"Tiep tuc (C/K)? "; cin>>Chon; Chon=toupper(Chon);
if ((N==100)||(Chon=='K'))
break;
}while (1); for(int I=0;I<N;++I)
{
Ng[I]->TinhLuong();
Ng[I]->Xuat();
}
return 0;
}
3.2. Hàm tạo và hàm huỷ đối với tính thừa kế
3.2.1. Xây dựng hàm tạo cđa lớp dẫn xuất
Khi khai báo một đối tượng có kiểu lớp được dẫn xuất từ một lớp cơ sở khác. Chương trình sẽ tự động gọi tới hàm tạo cđa lớp dẫn xuất. Tuy nhiên, thứ tự được gọi sẽ bắt đầu từ hàm tạo tương ứng cđa lớp cơ sở, sau đó đến hàm tạo cđa lớp dẫn xuất. Do đó, thông thường, trong hàm tạo cđa lớp dẫn xuất phải có hàm tạo cđa lớp cơ sở.
Cú pháp khai báo hàm tạo như sau:
<Tên hàm tạo cđa lớp dẫn xuất>([<Các tham số>]):
<Tên hàm tạo cđa lớp cơ sở>([<Các tham số>])
{
…// Khởi tạo các thuộc tính mới bổ sung cđa lớp dẫn xuất
};
Vì tên hàm tạo là trùng với tên lớp, nên có thể viết lại thành:
<Tên lớp dẫn xuất>([<Các tham số>]):
<Tên lớp cơ sở>([<Các tham số số>])
{
…// Khởi tạo các thuộc tính mới bổ sung cđa lớp dẫn xuất
};
Ví dụ 3.4:
Bus():Car()
{
…// Khởi tạo các thuộc tính mới bổ sung cđa lớp Bus
}
là một định nghĩa hàm tạo cđa lớp Bus thừa kế từ lớp Car. Định nghĩa này được thực hiện trong phạm vi khai báo lớp Bus. Đây là một hàm tạo không tham số, nó gọi tới hàm tạo không tham số cđa lớp Car.
Lưu ý:
nếu định nghĩa hàm tạo bên ngoài phạm vi lớp thì phải thêm tên lớp dẫn xuất và toán tử phạm vi “ ::” trước tên hàm tạo.
Giữa tên hàm tạo cđa lớp dẫn xuất và hàm tạo cđa lớp cơ sở, chỉ có một dấu hai chấm “ :” , nếu là hai dấu “ ::” thì trở thành toán tử phạm vi lớp.
nếu không chỉ rõ hàm tạo cđa lớp cơ sở sau dấu hai chấm “ :” chương trình sẽ tự động gọi hàm tạo ngầm định hoặc hàm tạo không có tham số cđa lớp cơ sở nếu hàm đó được định nghĩa tường minh trong lớp cơ sở.
Ví dụ, định nghĩa hàm tạo: Bus():Car()
{
…// Khởi tạo các thuộc tính mới bổ sung cđa lớp Bus
};
Có thể thay bằng: Bus()
{ //Gọi hàm tạo không tham số cđa lớp Car
…// Khởi tạo các thuộc tính mới bổ sung cđa lớp Bus
};
Ví dụ sau định nghĩa lớp Car có 3 thuộc tính với hai hàm tạo, sau đó định nghĩa lớp Bus có thêm thuộc tính label là số hiệu cđa tuyền xe buýt. Lớp Bus sẽ
được cài đặt hai hàm tạo tường minh, gọi đến hai hàm tạo tương ứng cđa lớp Car.