Tải bản đầy đủ (.ppt) (74 trang)

Bài giảng lập trình hướng đối tượng chương 4 sự kế thừa

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.68 MB, 74 trang )

Chương 4
Sự kế thừa

1


Nội dung
1.
2.
3.
4.
5.

Mở đầu
Kế thừa đơn
Phạm vi truy xuất
Phương thức thiết lập và huỷ bỏ
Con trỏ và kế thừa
2


4.1 Mở đầu
- Sự kế thừa là một đặc điểm của ngôn ngữ dùng để biểu diễn mối
quan hệ đặc biệt giữa các lớp. Các lớp được trừu tượng hóa và tổ
chức thành một sơ đồ phân cấp lớp.
- Kế thừa là một cơ chế trừu tượng hóa. Thủ tục và hàm là cơ chế
trừu tượng hóa cho giải thuật, record và struct là trừu tượng hóa
cho dữ liệu. Khái niệm lớp trong C++, kết hợp dữ liệu và thủ tục
để được kiểu dữ liệu trừu tượng với giao diện độc lập với cài đặt
và cho người sử dụng cảm giác thoải mái như kiểu dữ liệu có sẵn
- Sự kế thừa là một mức cao hơn của trừu tượng hóa. cung cấp một


cơ chế gom chung các lớp có liên quan với nhau thành một mức
khái quát hóa đặc trưng cho toàn bộ các lớp nói trên. Các lớp với
các đặc điểm tương tự nhau có thể được tổ chức thành một sơ đồ
phân cấp kế thừa. Lớp ở trên cùng là trừu tượng hóa của toàn bộ
các lớp ỏ bên dưới nó.
3


Mở đầu
 Quan hệ là 1: Kế thừa được sử dụng thông dụng nhất để biểu
diễn quan hệ là một.
• Một sinh viên là một người
• Một hình tròn là một hình ellipse
• Một tam giác là một đa giác

 Kế thừa tạo khả năng xây dựng lớp mới từ lớp đã có, trong
đó hàm thành phần được thừa hưởng từ lớp cha. Trong C++,
kế thừa còn định nghĩa sự tương thích, nhờ đó ta có cơ chế
chuyển kiểu tự động.
 Kế thừa vừa có khả năng tạo cơ chế khái quát hoá vừa có khả
năng chuyên biệt hoá.
 Kế thừa cho phép tổ chức các lớp chia sẻ mã chương trình
chung nhờ vậy có thể dễ dàng sửa chữa, nâng cấp hệ thống.
4


Mở đầu
 Kế thừa thường được dùng theo hai cách:
• Để phản ánh mối quan hệ giữa các lớp. Là công cụ để tổ
chức và phân cấp lớp dựa vào sự chuyên biệt hóa, trong đó

một vài hàm thành phần của lớp con là phiên bản hoàn
thiện hoặc đặc biệt hoá của phiên bản ở lớp cha. Trong C++
mối quan hệ này thường được cài đặt sử dụng:
 Kế thừa public.
 Hàm thành phần là phương thức ảo

• Để phản ánh sự chia sẻ mã chương trình giữa các lớp không
có quan hệ về mặt ngữ nghĩa nhưng có thể có tổ chức dữ
liệu và mã chương trình tương tự nhau. Trong C++, cơ chế
chia sẻ mã này thường được cài đặt dùng:
 Kế thừa private.
 Hàm thành phần không là phương thức ảo.
5


4.2 Kế thừa đơn
 Kế thừa có thể được thực hiện để thể hiện mối quan hệ 'là
một'.
 Xét hai khái niệm người và sinh viên với mối quan hệ tự
nhiên: một 'sinh viên' là một 'người'. Trong C++, ta có thể
biểu diễn khái niệm trên, một sinh viên là một người có thêm
một số thông tin và một số thao tác (riêng biệt của sinh viên).
 Ta tổ chức lớp sinh viên kế thừa từ lớp người. Lớp người
được gọi là lớp cha (superclass) hay lớp cơ sở (base class).
Lớp sinh viên được gọi là lớp con (subclass) hay lớp dẫn xuất
(derived class).

6



Kế thừa đơn
class Nguoi
{
friend class SinhVien;
char *HoTen;
int NamSinh;
public:
Nguoi(char *ht, int ns):NamSinh(ns) {HoTen = strdup(ht);}
~Nguoi() {delete [] HoTen;}
void An() const { cout << HoTen << " an 3 chen com";}
void Ngu() const { cout << HoTen << " ngu ngay 8 tieng";}
void Xuat() const;
friend ostream& operator << (ostream &os, Nguoi& p);
};

7


Kế thừa đơn
class SinhVien : public Nguoi
{
char *MaSo;
public:
SinhVien(char *ht, char *ms, int ns) : Nguoi(ht,ns) { MaSo =
strdup(ms);}
~SinhVien() {delete [] MaSo;}
void Xuat() const;
};
ostream& operator << (ostream &os, Nguoi& p)
{

return os << "Nguoi, ho ten: " << p.HoTen << " sinh " <<
p.NamSinh;
}

8


Kế thừa đơn
void Nguoi::Xuat() const
{
cout << "Nguoi, ho ten: " << HoTen << " sinh " << NamSinh;
}
void SinhVien::Xuat() const
{
cout << "Sinh vien, ma so: " << MaSo << ", ho ten: " << HoTen;
}

9


Kế thừa đơn
void main()
{
Nguoi p1("Le Van Nhan",1980);
SinhVien s1("Vo Vien Sinh", "200002541",1984);
cout << ”1.\n";
p1.An(); cout << "\n";
s1.An();cout << "\n";
cout << ”2.\n";
p1.Xuat(); cout << "\n";

s1.Xuat(); cout << "\n";
s1.Nguoi::Xuat(); cout << "\n";
cout << "3.\n";
cout << p1 << "\n";
cout << s1 << "\n";
}
10


Tự động kế thừa các đặc tính của lớp cha
 Khai báo
class SinhVien : public Nguoi
{
//...
};

Cho biết lớp sinh viên kế thừa từ lớp người. Khi đó sinh viên
được thừa hưởng các đặc tính của lớp người.
 Về mặt dữ liệu: Mỗi đối tượng sinh viên tự động có thành
phần dữ liệu họ tên và năm sinh của người.
 Về mặt thao tác: Lớp sinh viên được tự động kế thừa các thao
tác của lớp cha. Đây chính là khả năng sử dụng lại mã
chương trình.
 Riêng phương thức thiết lập không được kế thừa.
11


Tự động kế thừa các đặc tính của lớp cha
Nguoi p1("Le Van Nhan",1980);
SinhVien s1("Vo Vien Sinh", "200002541",1984);

p1.An(); cout << "\n";
s1.An();cout << "\n";

// Tu lop Nguoi

p1.Xuat(); cout << "\n";

 Kế thừa public như trên hàm ý rằng một đối tượng
sinh viên là một đối tượng người. Nơi nào chờ đợi
một đối tượng người có thể đưa vào đó một đối
tượng sinh viên (c/kiểu).
 Khả năng thừa hưởng các thao tác của lớp cơ sở
có thể được truyền qua vô hạn mức.
12


Định nghĩa lại thao tác ở lớp con
 Ta có thể định nghĩa lại các đặc tính ở lớp con đã có ở lớp
cha, việc định nghĩa chủ yếu là thao tác, bằng cách khai báo
giống hệt như ở lớp cha.
class SinhVien : public Nguoi
{
char *MaSo;
public:
//...
void Xuat() const;
};
void SinhVien::Xuat() const
{
cout << "Sinh vien, ma so: " << MaSo << ", ho ten: " << HoTen;

}
13


Định nghĩa lại thao tác ở lớp con
 Việc định nghĩa lại thao tác ở lớp con được thực hiện khi thao tác
ở lớp con khác thao tác ở lớp cha. Thông thường là các thao tác
xuất, nhập.
 Ta cũng có thể định nghĩa lại thao tác ở lớp con trong trường hợp
giải thuật ở lớp con đơn giản hơn (tô màu đa giác, tính modun của
số ảo...).
class DaGiac
{
// ...
void Ve() const;
void ToMau() const;
};
class HCN
{
void ToMau() const;
};
14


Định nghĩa lại thao tác ở lớp con
 Hoặc ở lớp con, thao tác không có tác dụng
class Ellipse
{
//...
public:

//...
void rotate(double rotangle){ //...}
};
class Circle:public Ellipse
{
public:
//...
void rotate(double rotangle){/* do nothing */}
};

15


4.3 Ràng buộc ngữ nghĩa ở lớp con
 Kế thừa có thể được áp dụng cho quan hệ kế thừa mang ý
nghĩa ràng buộc, đối tượng ở lớp con là đối tượng ở lớp cha
nhưng có dữ liệu bị ràng buộc.
• Hình tròn là Ellipse ràng buộc bán kính ngang dọc bằng
nhau.
• Số ảo là số phức ràng buộc phần thực bằng 0.
• Hình vuông là hình chữ nhật ràng buộc hai cạnh ngang và
dọc bằng nhau…
 Trong trường hợp này, các hàm thành phần phải bảo đảm sự
ràng buộc dữ liệu được tôn trọng. Lớp số ảo sau đây là một ví
dụ minh hoạ.

16


Ràng buộc ngữ nghĩa ở lớp con

class Complex
{
friend ostream& operator <<(ostream&, Complex);
friend class Imag;
double re, im;
public:
Complex(double r = 0, double i = 0):re(r), im(i){}
Complex operator +(Complex b);
Complex operator -(Complex b);
Complex operator *(Complex b);
Complex operator /(Complex b);
double Norm() const {return sqrt(re*re + im*im);}
};

17


Ràng buộc ngữ nghĩa ở lớp con
class Imag: public Complex
{
public:
Imag(double i = 0):Complex(0, i){}
Imag(const Complex &c) : Complex(0, c.im){}
Imag& operator = (const Complex &c)
{re = 0; im = c.im; return *this;}
double Norm() const {return fabs(im);}
};
void main()
{
Imag i = 1;

Complex z1(1,1), z3 = z1 - i; // z3 = (1,0)
i = Complex(5,2); // i la so ao (0,2)
Imag j = z1;
// j la so ao (0,1)
cout << "z1 = " << z1 << "\n";
cout << "i = " << i << "\n";
cout << "j = " << j << "\n";
}
18


Ràng buộc ngữ nghĩa ở lớp con
 Trong ví dụ trên lớp số ảo (Imag) kế thừa hầu hết các thao tác
của lớp số phức (Complex). Tuy nhiên ta muốn ràng buộc
mọi đối tượng thuộc lớp số ảo đều phải có phần thực bằng 0.
Vì vậy phải định nghĩa lại các hàm thành phần có thể vi
phạm điều này. Ví dụ phép toán gán phải được định nghĩa lại
để bảo đảm ràng buộc này.
class Imag: public Complex
{
public:
//...
Imag(const Complex &c) : Complex(0, c.im){}
Imag& operator = (const Complex &c)
{re = 0; im = c.im; return *this;}
};

19



Ràng buộc ngữ nghĩa ở lớp con
 Ví dụ sau minh hoạ thêm ràng buộc ngữ nghĩa ở lớp con
class HCN:public Hinh
{
Diem TrenTrai;
double rong, cao;
public:
HCN(Diem tt, double r, double c);
HCN(double ttx, double tty, double r, double c);
HCN():TrenTrai(4,6), rong(7), cao(4){}
virtual double DienTich() const {return rong*cao;}
virtual void Nhap();
virtual void Xuat();
virtual void PhongTo(double tiLe);
virtual void GianNgang(double tiLe);
virtual void GianDoc(double tiLe);
};
20


Ràng buộc ngữ nghĩa ở lớp con
void HCN::PhongTo(double tiLe)
{
rong *= tiLe;
cao *= tiLe;
}
void HCN::GianNgang(double tiLe)
{
TrenTrai.TinhTien(rong*(1-tiLe)/2, 0);
rong *= tiLe;

}
void HCN::GianDoc(double tiLe)
{
TrenTrai.TinhTien(0, cao*(1-tiLe)/2);
cao *= tiLe;
}

21


Ràng buộc ngữ nghĩa ở lớp con
class HV:public HCN
{
public:
HV(Diem tt, double canh):HCN(tt, canh, canh){}
HV(double ttx, double tty, double canh):HCN(ttx,tty,canh,canh){}
HV():HCN(7,8,6,6){}
char *TenLop() {return "Hinh Vuong";}
void Nhap();
void Xuat();
void GianNgang(double tiLe);
void GianDoc(double tiLe);
};

22


Ràng buộc ngữ nghĩa ở lớp con
void HV::GianNgang(double tiLe)
{

PhongTo(sqrt(tiLe));
}
void HV::GianDoc(double tiLe)
{
PhongTo(sqrt(tiLe));
}

23


4.4 Phạm vi truy xuất
 Khi thiết lập quan hệ kế thừa, ta vẫn phải quan tâm đến tính
đóng gói và che dấu thông tin. Điều này dẫn đến vấn đề xác
định ảnh hưởng của kế thừa đến phạm vi truy xuất các thành
phần của lớp. Hai vấn đề được đặt ra là:
 Truy xuất theo chiều dọc: Hàm thành phần của lớp con có
quyền truy xuất các thành phần riêng tư của lớp cha hay
không ? Vì chiều truy xuất là từ lớp con, cháu lên lớp cha nên
ta gọi là truy xuất theo chiều dọc
 Truy xuất theo chiều ngang: Các thành phần của lớp cha, sau
khi kế thừa xuống lớp con, thì thế giới bên ngoài có quyền
truy xuất thông qua đối tượng của lớp con hay không ? Trong
trường hợp này, ta gọi là truy xuất theo chiều ngang.
24


4.4.1 Truy xuất theo chiều dọc
 Lớp con có quyền truy xuất các thành phần của lớp cha hay
không, hay tổng quát hơn, nơi nào có quyền truy xuất các
thành phần của lớp cha, hoàn toàn do lớp cha quyết định.

Điều đó được xác định bằng thuộc tính truy xuất .
 Trong trường hợp lớp sinh viên kế thừa từ lớp người, truy
xuất theo chiều dọc có nghĩa liệu lớp sinh viên có quyền truy
xuất các thành phần họ tên, năm sinh của lớp người hay
không. Chính xác hơn một đối tượng sinh viên có quyền truy
xuất họ tên của chính mình nhưng được khai báo ở lớp người
hay không?
 Thuộc tính truy xuất là đặc tính của một thành phần của lớp
cho biết những nơi nào có quyền truy xuất thành phần đó.
25


×