Tải bản đầy đủ (.pdf) (43 trang)

Tính thừa kế

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 (71.25 KB, 43 trang )





Chương 6


Tính kế thừa










Giới thiệu tính kế thừa


Điều khiển truy cập lớp cơ sở


Sử dụng các thành viên được bảo vệ


Hàm tạo, hàm hủy và tính kế thừa


Tính đa kế thừa




Lớp cơ sở ảo








Chöông 6 Tính keá thöøa

164









































Chương 6 Tính kế thừa

165
I/ Giới thiệu tính kế thừa
(inheritance)


Tính kế thừa
là cơ chế nhờ đó một lớp có thể kế thừa các đặc điểm của một lớp khác.

Tính kế thừa hổ trợ khái niệm
phân loại theo thứ bậc
(hierachical classification) của
lớp, ngoài ra còn hổ trợ
tính đa hình
(polymorphism).


Lớp cơ sở
(base class) là lớp được kế thừa bởi một lớp khác.
Lớp dẫn xuất
(derive class) là lớp kế thừa từ một lớp cơ sở.

Lớp cơ sở
xác đònh các tính chất mà sẽ trở nên thông dụng cho các lớp dẫn xuất.
Nghiã là lớp cơ sở hiển thò mô tả tổng quát nhất một tập hợp các đặc điểm.

Một lớp dẫn xuất kế thừa các đặc điểm tổng quát này và bổ sung thêm các tính chất
riêng của lớp dẫn xuất.

Cú pháp khai báo cho
lớp dẫn xuất


class
derived_class_name
:


access_specifier
base_class_name
{

// body of class
} ;

base_class_name Tên lớp cơ sở
derived_class_name Tên lớp dẫn xuất
access_specifier
chỉ đònh truy cập bao gồm :
public
,
private

protected



Từ khoá
public
báo cho trình biên dòch biết rằng lớp cơ sở sẽ được kế thừa sao
cho mọi thành viên chung của lớp cơ sở cũng sẽ là các
thành viên chung của lớp
dẫn xuất
. Tuy nhiên, mọi
thành viên riêng
của lớp cơ sở
vẫn còn riêng đối với nó


và không được truy cập trực tiếp bởi lớp dẫn xuất.


Ví dụ 1.1
// A simple example of inheritance.
#include <iostream.h.h>



B


D
Hình 6.1 Sự kế thừa đơn

Chöông 6 Tính keá thöøa

166
// Define base class.
class
base
{
int i;
public:
void set_i(int n);
int get_i();
};

// Define derived class.

class
derived
:
public

base
{
int j;
public:
void set_j(int n);
int mul();
};

// Set value i in base.
void
base::set_i
(int n)
{
i = n;
}

// Return value of i in base.
int
base::get_i
() { return i; }

// Set value of j in derived.
void
derived::set_j
(int n)

{
j = n;
}

// Return value of base's i times derived's j.
int
derived::mul
()
{
// derived class can call base class public member functions
return j * get_i();
}
Chương 6 Tính kế thừa

167
int main()
{
derived ob;

ob.set_i(10); // load i in base
ob.set_j(4); // load j in derived

cout << ob.mul(); // displays 40

return 0;
}


Một


lớp cơ sở là không thuộc riêng về một lớp dẫn xuất.
Lớp cơ sở có thể được kế
thừa bởi nhiều lớp khác
.

Ví dụ 1.2
Lớp cơ sở chung Fruit có 2 lớp dẫn xuất Apple và Orange
// An example of class inheritance.
#include <iostream.h.h>
#include <string.h>

enum yn {no, yes};
enum color {red, yellow, green, orange};

void out(enum yn x);
char *c[] = {"red", "yellow", "green", "orange"};

// Generic fruit class.
class
fruit
{
// in this base, all elements are public
public:
enum yn annual;
enum yn perennial;
enum yn tree;
enum yn tropical;
enum color clr;
char name[40];
};

Chöông 6 Tính keá thöøa

168
// Derive Apple class.
class
Apple
:
public

fruit
{
enum yn cooking;
enum yn crunchy;
enum yn eating;
public:
void seta(char *n, enum color c, enum yn ck, enum yn crchy, enum yn e);
void show();
};

// Derive orange class.
class
Orange
:
public

fruit
{
enum yn juice;
enum yn sour;
enum yn eating;

public:
void seto(char *n, enum color c, enum yn j, enum yn sr, enum yn e);
void show();
};

void
Apple::seta
(char *n, enum color c, enum yn ck, enum yn crchy,
enum yn e)
{
strcpy(name, n);
annual = no;
perennial = yes;
tree = yes;
tropical = no;
clr = c;
cooking = ck;
crunchy = crchy;
eating = e;
}

void
Orange::seto
(char *n, enum color c, enum yn j, enum yn sr, enum yn e)
{
strcpy(name, n);
Chöông 6 Tính keá thöøa

169
annual = no;

perennial = yes;
tree = yes;
tropical = yes;
clr = c;
juice = j;
sour = sr;
eating = e;
}
void
Apple::show
()
{
cout << name << " apple is: " << "\n";
cout << "Annual: "; out(annual);
cout << "Perennial: "; out(perennial);
cout << "Tree: "; out(tree);
cout << "Tropical: "; out(tropical);
cout << "Color: " << c[clr] << "\n";
cout << "Good for cooking: "; out(cooking);
cout << "Crunchy: "; out(crunchy);
cout << "Good for eating: "; out(eating); cout << "\n";
}

void
Orange::show
()
{
cout << name << " orange is: " << "\n";
cout << "Annual: "; out(annual);
cout << "Perennial: "; out(perennial);

cout << "Tree: "; out(tree);
cout << "Tropical: "; out(tropical);
cout << "Color: " << c[clr] << "\n";
cout << "Good for juice: "; out(juice);
cout << "Sour: "; out(sour);
cout << "Good for eating: "; out(eating); cout << "\n";
}



Chương 6 Tính kế thừa

170
void out(enum yn x)
{
if(x==no) cout << "no\n";
else cout << "yes\n";
}

int main()
{
Apple a1, a2;
Orange o1, o2;

a1.seta("Red Delicious", red, no, yes, yes);
a2.seta("Jonathan", red, yes, no, yes);
o1.seto("Navel", orange, no, no, yes);
o2.seto("Valencia", orange, yes, yes, no);

a1.show();

a2.show();

o1.show();
o2.show();
return 0;
}


Bài tập I

1. Cho lớp cơ sở sau
class area_cl {
public:
double height;
double width;
};

hãy tạo 2 lớp dẫn xuất box và isosceles kế thừa lớp area_cl. Với mỗi lớp hãy tạo
hàm area() lần lượt trả về diện tích của một hộp hay một tam giác cân. Dùng các
hàm tạo được tham số hoá để khởi đầu height và width.
Chương 6 Tính kế thừa

171
II/ Điều khiển truy cập lớp cơ sở

Chỉ đònh truy cập (
access_specifier
) xác đònh cách mà các phần tử của lớp cơ sở
được kế thừa bởi lớp dẫn xuất.



Từ khoá
private
chỉ đònh

các thành viên chung lớp cơ sở trở thành các
thành
viên riêng của lớp dẫn xuất,
nhưng những thành viên này vẫn còn được truy cập
bởi các hàm thành viên của lớp dẫn xuất.

Ví dụ 2.1
#include <iostream.h>

class base {
int x;
public:
void setx(int n) { x = n; }
void showx() { cout << x << '\n'; }
};

// Inherit as public.
class
derived
:
public

base
{
int y;

public:
void sety(int n) { y = n; }
void showy() { cout << y << '\n'; }
};

int main()
{
derived ob;

ob.setx(10); // access member of base class
ob.sety(20); // access member of derived class

ob.showx(); // access member of base class
ob.showy(); // access member of derived class

Chương 6 Tính kế thừa

172
return 0;
}


Ví dụ 2.2
Lớp dẫn xuất không thể truy cập đến các thành viên riêng của lớp cơ
sở

class base {
int x;
public:
void setx(int n) { x = n; }

void showx() { cout << x << '\n'; }
};

// Inherit as public - this has an error!
class derived :
public
base {
int y;
public:
void sety(int n) { y = n; }

/* Cannot access private member of base class.
x is a private member of base and not available within derived. */
void show_sum() { cout <<
x
+ y << '\n'; } // Error!
void showy() { cout << y << '\n'; }
};


Ví dụ 2.3
Lớp dẫn xuất kế thừa lớp cơ sở với chỉ đònh private
// This program contains an error.
#include <iostream.h>

class base {
int x;
public:
void setx(int n) { x = n; }
void showx() { cout << x << '\n'; }

};
Chương 6 Tính kế thừa

173
// Inherit base as private.
class derived :
private
base {
int y;
public:
void sety(int n) { y = n; }
void showy() { cout << y << '\n'; }
};

int main()
{
derived ob;

ob.setx(10); // ERROR - now private to derived class
ob.sety(20); // access member of derived class - OK
ob.showx(); // ERROR - now private to derived class
ob.showy(); // access member of derived class - OK

return 0;
}

@ Lưu ý
Trong hàm main vẫn có thể truy cập các thành viên chung cuả lớp cơ
sở
base base_ob;

base_ob.setx(1); // is legal because base_ob is of type base


Ví dụ 2.4
Lớp dẫn xuất kế thừa lớp cơ sở với chỉ đònh private, các thành viên vẫn
còn được
truy cập bên trong lớp dẫn xuất
.
// This program is fixed.
#include <iostream.h>

class base {
int x;
public:
void setx(int n) { x = n; }
void showx() { cout << x << '\n'; }
};
Chöông 6 Tính keá thöøa

174
// Inherit base as private.
class derived :
private
base {
int y;
public:
// setx is accessible from within derived
void setxy(int n, int m) {
setx(n)
; y = m; }

// showx is accessible from within derived
void showxy() {
showx()
; cout << y << '\n'; }
};

int main()
{
derived ob;

ob.setxy(10, 20);
ob.showxy();
return 0;
}




















Chương 6 Tính kế thừa

175
Bài tập II

1. Xét đoạn chương trình sau
#include <iostream.h>

class mybase {
int a, b;
public:
int c;
void setab(int i, int j) { a = i; b = j; }
void getab(int &i, int &j) { i = a; j = b; }
};

class derived1 :
public
mybase {
// ...
};

class derived2 :
private
mybase {
// ...
};


int main()
{
derived1 o1;
derived2 o2;
int i, j;

// ...
}

Trong hàm main() câu lệnh nào sau đây là hợp lệ :
A. o1.getab(i,j) ;
B. o2.getab(i,j) ;
C. o1.c = 10 ;
D. o2.c = 10 ;
2. Điều gì xảy ra khi một thành viên riêng được kế thừa như một thành viên chung ?
Điều gì xảy ra khi nó được kế thừa như một thành viên riêng ?
Chương 6 Tính kế thừa

176
III/ Sử dụng các thành viên được bảo vệ
(protected members)


Với các chỉ đònh truy cập
public

private
, một lớp dẫn xuất không truy cập được
các thành viên riêng của lớp cơ sở. Tuy nhiên, sẽ có những lúc muốn một thành viên

của lớp cơ sở vẫn là riêng nhưng vẫn cho phép lớp dẫn xuất truy cập tới nó.


Chỉ đònh truy cập
protected
, tương đương với chỉ đònh
private
với một ngoại lệ
duy nhất là các
thành viên được bảo vệ
(protected members
)
của lớp cơ sở có thể
được truy cập đối với các thành viên của một lớp dẫn xuất từ lớp cơ sở đó.

Bên ngoài lớp cơ sở hoặc lớp dẫn xuất, các
thành viên được bảo vệ
không thể
được truy cập.

Dạng tổng quát của khai báo lớp :

class
class_name
{

// private members
protected :
// protected members
public :

// public members
};

Khi một
thành viên được bảo vệ
của một lớp cơ sở được kế thừa bởi lớp dẫn xuất với
chỉ đònh
public
, nó trở thành
thành viên được bảo vệ của lớp dẫn xuất
.

Nếu lớp dẫn xuất được kế thừa với chỉ đònh
private
, thì một thành viên được bảo vệ
của lớp cơ sở trở thành
thành viên riêng của lớp dẫn xuất
.

Lớp cơ sở có thể được kế thừa với chỉ đònh
protected
bởi lớp dẫn xuất, khi đó các
thành viên chung và được bảo vệ của lớp cơ sở trở thành các thành viên được bảo vệ
của lớp dẫn xuất.

Còn các thành viên riêng của lớp cơ sở vẫn còn riêng đối với lớp cơ sở và không
được truy cập bởi lớp dẫn xuất.

Chương 6 Tính kế thừa


177
Ví dụ 3.1
Truy cập các thành viên chung, riêng và được bảo vệ của lớp cơ sở
#include <iostream.h>

class samp {
// private by default
int a;
protected: // still private relative to samp
int b;
public:
int c;

samp(int n, int m) { a = n; b = m; }
int geta() { return a; }
int getb() { return b; }
};

int main()
{
samp ob(10, 20);

// ob.b = 99; Error! b is protected and thus private
ob.c = 30; // OK, c is public

cout << ob.geta() << ' ';
cout << ob.getb() << ' ' << ob.c << '\n';

return 0;
}



Ví dụ 3.2
Các
thành viên được bảo vệ
được kế thừa như thành viên chung
#include <iostream.h>

class
base
{
protected :
// private to base
int a, b; // but still accessible by derived
public:
Chương 6 Tính kế thừa

178
void setab(int n, int m) { a = n; b = m; }
};

class
derived
:
public

base
{
int c;
public:

void setc(int n) { c = n; }

// this function has access to a and b from base
void showabc() {
cout << a << ' ' << b << ' ' << c << '\n';
}
};

int main()
{
derived ob;

// a and b are not accessible here because they are private to both base and
derived.
ob.setab(1, 2);
ob.setc(3);

ob.showabc();
return 0;
}


Ví dụ 3.3
Các
thành viên được bảo vệ
được kế thừa bởi chỉ đònh
protected

// This program will not compile.
#include <iostream.h>


class base {
protected :
// private to base
int a, b; // but still accessible by derived
public:

Chöông 6 Tính keá thöøa

179
void setab(int n, int m)
{ a = n;
b = m;
}
};


class
derived
:
protected

base
{ // inherit as protected
int c;
public:
void setc(int n) { c = n; }

// this function has access to a and b from base
void showabc() {

cout << a << ' ' << b << ' ' << c << '\n';
}
};

int main()
{
derived ob;

// ERROR: setab() is now a protected member of base.
ob.setab(1, 2); // setab() is not accessible here.
ob.setc(3);
ob.showabc();

return 0;
}








Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×