Chương 9. Tha kế
Trong thc tế hu hết các lp có th kế tha t các lp có trước mà không cn
định nghĩa li mi hoàn toàn. Ví d xem xét mt lp được đặt tên là RecFile
đại din cho mt tp tin gm nhiu mu tin và mt lp khác được đặt tên là
SortedRecFile đại din cho mt tp tin gm nhiu mu tin được sp xếp. Hai
lp này có th có nhiu đim chung. Ví d, chúng có th có các thành viên
hàm ging nhau nhưInsert, Delete, và Find, cũng như là thành viên d liu
ging nhau. SortedRecFile là mt phiên bn đặc bit ca RecFile vi thuc tính
các mu tin ca nó được t chc theo th t được thêm vào. Vì thế hu hết
các hàm thành viên trong c hai lp là ging nhau trong khi mt vài hàm mà
ph thuc vào yếu t tp tin được sp xếp thì có th khác nhau. Ví d, hàm
Find có th là khác trong lp SortedRecFile bi vì nó có th nh vào yếu t
thun li là tp tin được sp để thc hin tìm kiếm nh phân thay vì tìm tuyến
tính như hàm Find ca lp RecFile.
Vi các thuc tính được chia s ca hai lp này thì vic định nghĩa chúng
mt cách độc lp là rt dài dòng. Rõ ràng điu này dn ti vic phi sao chép
li mã đáng k. Mã không ch mt thi gian lâu hơn để viết nó mà còn khó có
th được bo trì hơn: mt thay đổi ti bt k thuc tính chia s nào có th
phi được sa đổi ti c hai lp.
Lp trình hướng đối tượng cung cp mt k thut thun li gi là tha
kế để gii quyết vn đề này. Vi tha kế thì mt lp có th tha kế nhng
thuc tính ca mt lp đã có trước. Chúng ta có th s dng tha kế để định
nghĩa nhng thay đổi ca mt lp mà không cn định nghĩa li lp mi t
đầu. Các thuc tính chia s ch được định nghĩa mt ln và được s dng li
khi cn.
Trong C++ tha kế được h tr bi các lp dn xut (derived class).
Lp dn xut thì ging như lp gc ngoi tr định nghĩa ca nó da trên mt
hay nhiu lp có sn đưc gi là lp cơ s (base class). Lp dn xut có th
chia s nhng thuc tính đã chn (các thành viên hàm hay các thành viên d
liu) ca các lp cơ s ca nó nhưng không làm chuyn đổi định nghĩa ca
bt k lp cơ s nào. Lp dn xut chính nó có th là lp cơ s ca mt lp
dn xut khác. Quan h tha kế gia các lp ca mt chương trình được gi
quan h cp bc lp (class hierarchy).
Lp dn xut cũng được gi là lp con (subclass) bi vì nó tr thành cp
thp hơn ca lp cơ s trong quan h cp bc. Tương t mt lp cơ s có th
được gi là lp cha (superclass) bi vì t nó có nhiu lp khác có th được
dn xut.
Chương 9: Tha kế
148
9.1. Ví d minh ha
Chúng ta s định nghĩa hai lp nhm mc đích minh ha mt s khái nim
lp trình trong các phn sau ca chương này. Hai lp được định nghĩa trong
Danh sách 9.1 và h tr vic to ra mt thư mc các đối tác cá nhân.
Danh sách 9.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream.h>
#include <string.h>
class Contact {
public:
Contact(const char *name, const char *address, const char *tel);
~Contact (void);
const char* Name (void) const {return name;}
const char* Address(void) const {return address;}
const char* Tel(void) const {return tel;}
friend ostream& operator << (ostream&, Contact&);
private:
char *name; // ten doi tac
char *address; // dia chi doi tac
char *tel; // so dien thoai
};
//-------------------------------------------------------------------
class ContactDir {
public:
ContactDir(const int maxSize);
~ContactDir(void);
void Insert(const Contact&);
void Delete(const char *name);
Contact* Find(const char *name);
friend ostream& operator <<(ostream&, ContactDir&);
private:
int Lookup(const char *name);
Contact **contacts; // danh sach cac doi tac
int dirSize; // kich thuoc thu muc hien tai
int maxSize; // kich thuoc thu muc toi da
};
Chú gii
3 Lp Contact lưu gi các chi tiết ca mt đối tác (nghĩa là, tên, địa ch, và
s đin thoi).
18 Lp ContactDir cho phép chúng ta thêm, xóa, và tìm kiếm mt danh sách
các đối tác.
22 Hàm Insert xen mt đối tác mi vào thư mc. Điu này s viết chng lên
mt đối tác tn ti (nếu có) vi tên ging nhau.
23 Hàm Delete xóa mt đối tác (nếu có) mà tên ca đối tác trùng vi tên đã
cho.
Chương 9: Tha kế
149
24 Hàm Find tr v mt con tr ti mt đối tác (nếu có) mà tên ca đối tác
khp vi tên đã cho.
27 Hàm Lookup tr v ch s v trí ca mt đối tác mà tên ca đối tác khp
vi tên đã cho. Nếu không tn ti thì sau đó hàm Lookup tr v ch s ca
v trí mà ti đó mà mt đầu vào như thế s được thêm vào. Hàm Lookup
được định nghĩa như là riêng (private) bi vì nó là mt hàm ph được s
dng bi các hàm Insert, Delete, và Find.
Cài đặt ca hàm thành viên và hàm bn như sau:
Contact::Contact (const char *name,
const char *address, const char *tel)
{
Contact::name = new char[strlen(name) + 1];
Contact::address = new char[strlen(address) + 1];
Contact::tel = new char[strlen(tel) + 1];
strcpy(Contact::name, name);
strcpy(Contact::address, address);
strcpy(Contact::tel, tel);
}
Contact::~Contact (void)
{
delete name;
delete address;
delete tel;
}
ostream& operator << (ostream &os, Contact &c)
{
os << "(" << c.name << " , "
<< c.address << " , " << c.tel << ")";
return os;
}
ContactDir::ContactDir (const int max)
{
typedef Contact *ContactPtr;
dirSize = 0;
maxSize = max;
contacts = new ContactPtr[maxSize];
};
ContactDir::~ContactDir (void)
{
for (register i = 0; i < dirSize; ++i)
delete contacts[i];
delete [] contacts;
}
void ContactDir::Insert (const Contact& c)
{
if (dirSize < maxSize) {
int idx = Lookup(c.Name());
if (idx > 0 &&
strcmp(c.Name(), contacts[idx]->Name()) == 0) {
delete contacts[idx];
Chương 9: Tha kế
150
} else {
for (register i = dirSize; i > idx; --i) // dich phai
contacts[i] = contacts[i-1];
++dirSize;
}
contacts[idx] = new Contact(c.Name(), c.Address(), c.Tel());
}
}
void ContactDir::Delete (const char *name)
{
int idx = Lookup(name);
if (idx < dirSize) {
delete contacts[idx];
--dirSize;
for (register i = idx; i < dirSize; ++i) // dich trai
contacts[i] = contacts[i+1];
}
}
Contact *ContactDir::Find (const char *name)
{
int idx = Lookup(name);
return (idx < dirSize &&
strcmp(contacts[idx]->Name(), name) == 0)
? contacts[idx]
: 0;
}
int ContactDir::Lookup (const char *name)
{
for (register i = 0; i < dirSize; ++i)
if (strcmp(contacts[i]->Name(), name) == 0)
return i;
return dirSize;
}
ostream &operator << (ostream &os, ContactDir &c)
{
for (register i = 0; i < c.dirSize; ++i)
os << *(c.contacts[i]) << '\n';
return os;
}
Hàm main sau thc thi lp ContactDir bng cách to ra mt thư mc nh
và gi các hàm thành viên:
int main (void)
{
ContactDir dir(10);
dir.Insert(Contact("Mary", "11 South Rd", "282 1324"));
dir.Insert(Contact("Peter", "9 Port Rd", "678 9862"));
dir.Insert(Contact("Jane", "321 Yara Ln", "982 6252"));
dir.Insert(Contact("Jack", "42 Wayne St", "663 2989"));
dir.Insert(Contact("Fred", "2 High St", "458 2324"));
cout << dir;
cout << "Find Jane: " << *dir.Find("Jane") << '\n';
dir.Delete("Jack");
Chương 9: Tha kế
151
cout << "Deleted Jack\n";
cout << dir;
return 0;
};
Khi chy nó s cho kết qu sau:
(Mary , 11 South Rd , 282 1324)
(Peter , 9 Port Rd , 678 9862)
(Jane , 321 Yara Ln , 982 6252)
(Jack , 42 Wayne St , 663 2989)
(Fred , 2 High St , 458 2324)
Find Jane: (Jane , 321 Yara Ln , 982 6252)
Deleted Jack
(Mary , 11 South Rd , 282 1324)
(Peter , 9 Port Rd , 678 9862)
(Jane , 321 Yara Ln , 982 6252)
(Fred , 2 High St , 458 2324)
9.2. Lp dn xut đơn gin
Chúng ta mun định nghĩa mt lp gi là SmartDir ng x ging như là lp
ContactDir và theo dõi tên ca đối tác mi va được tìm kiếm gn nht. Lp
SmartDir được định nghĩa tt nht như là mt dn xut ca lp ContactDir như
được minh ha bi Danh sách 9.2.
Danh sách 9.2
1
2
3
4
5
6
7
8
class SmartDir : public ContactDir {
public:
SmartDir(const int max) : ContactDir(max) {recent = 0;}
Contact* Recent (void);
Contact* Find (const char *name);
private:
char * recent; // ten duoc tim gan nhat
};
Chú gii
1 Phn đầu ca lp dn xut chèn vào các lp cơ s mà nó tha kế. Mt
du hai chm (:) phân bit gia hai phn. đây, lp ContactDir được đặc
t là lp cơ s lp SmartDir được dn xut. T khóa public phía trước
lp ContactDir ch định rng lp ContactDir được s dng như mt lp cơ
s chung.
3 Lp SmartDir có hàm xây dng ca nó, hàm xây dng này triu gi hàm
xây dng ca lp cơ s trong danh sách khi to thành viên ca nó.
4 Hàm Recent tr v mt con tr ti đối tác được tìm kiếm sau cùng (hoc 0
nếu không có).
5 Hàm Find được định nghĩa li sao cho nó có th ghi nhn đầu vào được
tìm kiếm sau cùng.
7 Con tr recent được đặt ti tên ca đầu vào đã được tìm sau cùng.
Chương 9: Tha kế
152