CHƢƠNG 5 QUAN HỆ GIỮA CÁC LỚP
1. QUAN HỆ
1.4. Quan hệ tổng quát hĩa/đặc biệt hĩa (IS-A)
Đây là quan hệ đã đƣợc trình bày trong chƣơng kế thừa. Quan hệ tổng quát hĩa/ đặc biệt hĩa đƣợc sử dụng cho mối liên hệ giữa 2 lớp đối tƣợng A và B trong trƣờng hợp lớp này là một trƣờng hợp tổng quát hay đặc biệt hĩa của lớp kia.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 99 Chẳng hạn, lớp Đ ngVật là trƣờng hợp tổng quát hĩa của lớp Mèo, lớp u Mơ hình UML: Động Vật Mèo Cừu
Trong ví dụ trên, chúng ta xem “con mèo là một Đ ng vật” hay “con c u là
một Đ ng vật” nên chúng sẽ thừa hƣởng tất cả các tính chất nhƣ một Đ ng vật 1.5. Quan hệ bạn bè (friend)
Trong mối quan hệ giữa các lớp đối tƣợng, quan hệ bạn là quan hệ cho phép lớp bạn của mình đƣợc quyền truy xuất đến tồn bộ nội dung (dữ liệu hay phƣơng thức) của mình, kể cả các thành phần private.
Khi lớp B là bạn của lớp A: thì B cĩ quyền truy xuất và sử dụng tất cả các thành phần của lớp A.
Mơ hình UML: B
A
Ghi chú: Khác với 2 loại quan hệ bao hàm và quan hệ đặc biệt hĩa, quan hệ bạn bè khơng tự hủy đối tƣợng của lớp bạn khi lớp này kết thúc chu trình sống.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 100
2. CÀI ĐẶT QUAN HỆ
2.1. Quan hệ HAS-A
Để cài đặt mối quan hệ HAS-A, chúng ta thƣờng sử dụng thành phần dữ liệu của một lớp để liên kết với lớp kia.
Ví dụ cài đặt mối quan hệ giữa lớp tam giác và điểm: class Diem
{ private:
double x,y; public:
double xemX() const; double xemY() const;
void ganX(const double &a); void ganY(const double &b); }; //……………………… class TamGiac { private: Diem arrDinh[3]; public:
double tinhDienTich() const; double tinhChuVi() const; };
Bảng: Lớp Điểm là một bộ phận của lơp tam giác
Trong cách cài đặt này, khi một đối tƣợng TamGiac đƣợc tạo ra, trƣớc khi chạy phƣơng thức khởi tạo tƣơng ứng của lớp TamGiac, phƣơng thức khởi tạo của 3 đỉnh tam giác (lớp Điểm) sẽ đƣợc gọi chạy trƣớc. Tƣơng tự nhƣ vậy nhƣng theo thứ tự ngƣợc lại đối với phƣơng thức hủy trong tình huống đối tƣợng này hết chu kỳ sống. Nghĩa là, sau khi phƣơng thức hủy của lớp TamGiac thực hiện xong thì lần
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 101 lƣợt phƣơng thức hủy của 3 đối tƣợng Điểm (đỉnh của tam giác) sẽ đƣợc gọi thực hiện.
Tuy nhiên, trong một số trƣờng hợp (thƣờng là arrgregation), khi mối quan hệ bao hàm đƣợc thể hiện bằng một con trỏ trong thành phần dữ liệu thay vì một đối tƣợng cụ thể, chúng ta phải tự thực hiện việc tạo lập và hủy cho từng thành phần của lớp bộ phận.
Ví dụ cài đặt về quan hệ giữa lớp Xe và Hành khách Class XE
{ public:
XE(); // lƣu ý phải tự tạo lập hành khách nếu cần ~XE(); //lƣu ý phải tự hủy hành khách
private:
HanhKhach *arrKhach; // danh sách hành khách int n;
};
Bảng: Tự tạo lập và hủy các đối tƣợng thành phần trong trƣờng hợp dùng con trỏ để thể hiện quan hệ bao hàm/bộ phận
2.2. Quan hệ IS-A
Để cài đặt mối quan hệ tổng quát hĩa/đặc biệt hĩa, chúng ta sử dụng kế thừa public.
Ví dụ về cài đặt mối quan hệ tổng quát hĩa/ đặc biệt hĩa class DongVat
{ public:
virtual void Keu()=0; // phƣơng thức thuần ảo };
class Meo:public DongVat {
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 102 virtual void Keu()
{
cout<<”Meo meo”<<endl; }
};
//………………………………… class Cuu:public DongVat
{ public:
virtual void Keu() {
cout<<”Be…Be..”<<endl; }
};
Bảng: lớp Động Vật là trƣờng hợp tổng quát của Mèo và Cừu
Trong cách cài đặt này, lớp mèo và lớp Cừu cùng kế thừa public từ lớp Động vật. Khi đĩ, chúng ta diễn giải mối quan hệ giữa các lớp đĩ theo cách: “Con mèo là một động vật” hay “con cừu là một động vật” (diễn giải theo quan hệ IS-A).
Trong lớp Động vật, phƣơng thức Keu() là phƣơng thức thuần ảo và bắt buộc phải đƣợc viết lại trong lớp đối tƣợng kế thừa nĩ. Cụ thể, lớp Mèo và Cừu đã viết lại phƣơng thức Keu() theo cách riêng của mình.
Do “con mèo là một động vật” hay “con cừu là một động vật” nên việc chuyển đổi kiểu dữ liệu từ Mèo* hay Cừu* thành DongVat* là hồn tồn hợp lệ và dễ dàng.
Cũng cân nhắc lại rằng, trong kế thừa, khi một đối tƣợng của lớp kế thừa đƣợc tạo lập, trƣớc khi các phƣơng thức khởi tạo của lớp kế thừa thực hiện thì các phƣơng thức khởi tạo của lớp cơ sở sẽ đƣợc gọi để thực hiện trƣớc. Đối với các phƣơng thức hủy thì chúng đƣợc gọi theo thứ tự ngƣợc lại.
Lƣu ý: Chỉ sử dụng kế thừa public (khơng đƣợc sử dụng kế thừa private hay protected) để cài đặt cho mối quan hệ IS-A.
2.3. Quan hệ bạn
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 103 Ví dụ cài đặt về mối quan hệ bạn:
class A { private:
int a; public:
friend class B; // A xem lớp B là bạn hay B là bạn của A }; //……………………… class B { private: A test; public: void testTruyXuat() {
test.a = 7; // đƣợc truy xuất trực tiếp a }
};
Bảng: Lớp B là bạn lớp A
Trong trƣờng hợp này lớp A xem lớp B là bạn và lớp B cĩ quyền truy xuất đến bất kỳ thành phần nào của lớp A.
Lƣu ý: từ khĩa friend cĩ thể làm mất đi tính chất bao bọc và che dấu thành phần dữ liệu của lớp A trong thiết kế ban đầu. Do vậy, khi muốn sử dụng loại quan hệ này, chúng ta cần phải cân nhắc và xác định kỹ tính cần thiết của nĩ. Nếu sử dụng hợp lý, mối quan hệ này sẽ tạo thêm tính linh hoạt cho tính che dấu dữ liệu của đối tƣợng.
TỔNG KẾT CHƢƠNG
Giữa các lớp đối tƣợng sẽ cĩ 3 loại quan hệ: - Mối quan hệ bao hàm / phụ thuộc
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 104 - Mối quan hệ bạn bè
CÂU HỎI VÀ BÀI TẬP
1. Nêu các loại quan hệ giữa các lớp đối tƣợng?
2. Cài đặt mối quan hệ giữa lớp điểm và hình trịn. Sau đĩ tính diện tích và chu vi của hình trịn
3. Cài đặt mối quan hệ giữa các lớp đối tƣợng trong bài tốn sau: Cĩ 2 loại hình:
- Hình tam giác: biểu diễn bởi 3 đỉnh.
- Hình chữ nhật: biểu diễn bởi 2 điểm trên trái và dƣới phải. (1). Xây dựng các phƣơng thức nhập xuất cho các hình. (2). Giả sử cĩ sẵn một danh sách các hình.
a. Nhập danh sách các hình
b. Xuất thơng tin của từng hình trong danh sách đĩ. c. Xây dựng thêm phƣơng thức tính chu vi các hình
d. Xây dựng hàm kiểm tra xem hình nào cĩ, hình nào cĩ chu vi lớn nhất. Tại chƣơng trình chính cho phép xuất ra hình cĩ chu vi lớn nhất
Sau đĩ, giả sử cĩ thêm loại hình mới là hình trịn.
- Hình trịn: biểu diễn bởi tâm và bán kính. Khi đĩ, chƣơng trình sẽ phải đƣợc chỉnh sửa nhƣ thế nào?
4. Xây dựng quan hệ giữa lớp Điểm (trong mặt phẳng tọa độ hai chiều) và lớp tam giác (biết mỗi tam giác đƣợc tạo thành bởi 3 đối tƣợng điểm của lớp Điểm nĩi trên).
a) Trong mỗi lớp hãy xây dựng các phƣơng thức nhập, xuất dữ liệu. b) Trong lớp tam giác hãy xây dựng:
i. Phƣơng thức tính chu vi tam giác ii. Phƣơng thức tính diện tích tam giác
Xây dựng chƣơng trình cho phép tạo ra các đối tƣợng tam giác, sau đĩ xuất ra chu vi và diện tích của mỗi tam giác.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 105
CHƢƠNG 6. TEMPLATE
MỤC TIÊU
Sau khi học xong sinh viên cĩ khả năng:
- Trình bày đƣợc ý nghĩa của template (khuơn mẫu) - Cài đặt đƣợc các khuơn mẫu đơn giản
1. Ý nghĩa.
Trong quá trình phát triển các sản phẩm phần mềm, đơi khi chúng ta gặp trƣờng hợp cần phải cài đặt cùng một hàm hay một lớp nhiều lần cho nhiều kiểu dữ liệu khác nhau. Thay vì chúng ta phải cài đặt lại hồn tồn nội dung các hàm hay các lớp này với kiểu dữ liệu mới, ngơn ngữ C++ cho phép chúng ta tham số hĩa kiểu dữ liệu cho hàm hoặc cho lớp. Việc tham số hĩa cho hàm hay cho lớp sẽ giúp chúng ta chỉ cài đặt một lần với kiểu dữ liệu tổng quát và khi sử dụng, tùy vào kiểu dữ liệu tƣơng ứng thì hàm hay lớp với kiểu dữ liệu đĩ sẽ đƣợc thực thi.
2. Function template (khuơn mẫu hàm)
Chẳng hạn, chúng ta cần cài đặt hàm hốn đổi giá trị của 2 biến số nguyên. Sau đĩ, chúng ta lại cần cài đặt một hàm tƣơng tự cho 2 biến số thực. Trong trƣờng hợp đĩ, thay vì chúng ta viết 2 hàm tƣơng tự nhau nhƣng chỉ khác kiểu dữ liệu nhƣ trong bảng sau:
void doiGiaTri(int &a, int &b) { int tam; tam=a; a=b; b=tam; }
void doiGiaTri(float &a, float &b) { float tam; tam=a; a=b; b=tam; }
Thì chúng ta hồn tồn cĩ thể cài đặt bằng một hàm chung thơng qua việc tham số hĩa kiểu dữ liệu T tổng quá nhƣ trong bảng sau:
template<class T>
void doiGiaTri(T &a, T &b) { T tam;
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 106 tam=a;
a=b; b=tam; }
Khi cần sử dụng hàm này, chúng ta chỉ cần gọi hàm doiGiaTri(x,y) với x và y cĩ thể cùng int hoặc cùng float đều đƣợc.
Cú pháp cho việc tham số hĩa:
template <class T>
KiểuTrảVề TênHàm (Danh sách các tham số) {
//nội dung của hàm }
Trong ví dụ trên, các từ template và class là các từ khĩa nên chúng ta phải áp dụng đúng nhƣ vậy. Tuy nhiên, T khơng phải là một từ khĩa mà là một tên riêng thể hiện tên 1 kiểu dữ liệu tổng quát. Chúng ta cĩ thể tự đặt bằng các tên khác tùy ý miễn là khơng vi phạm quy tắc đặt tên.
Khi gọi các hàm đƣợc tham số hĩa dữ liệu, chúng ta cĩ thể gọi bình thƣờng nhƣ các hàm thơng dụng. Chẳng hạn trogn ví dụ về hàm doiGiaTri ở phần trên,
chúng ta sẽ gọi nhƣ sau: int x=3, y=7; float a=2.5, b=1.3; doiGiaTri(x,y); doiGiaTri(a,b);
Khi đĩ các hàm doiGiaTri() với kiểu dữ liệu tƣơng ứng sẽ đƣợc gọi phát sinh ngầm định ở bên dƣới và đƣợc gọi thực thi phù hợp. Đối với lời gọi hàm doiGiaTri(x,y), thì kiểu T đƣợc thay bởi int và hàm doiGiaTri<int>(int &, int &) sẽ đƣợc sử dụng. Trong khi đĩ, đối với lời gọi hàm doiGiaTri(a,b) thì T thay đổi float và hàm doiGiaTri<float>(float& , float&) sẽ đƣợc dùng.
Trong trƣờng hợp tham số hĩa nhiều hơn một kiểu dữ liệu, chúng ta sẽ cài đặt theo cú pháp sau:
template <class T, class U> KiểuTrảVề TênHàm (T x, U y) {
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 107
//nội dung của hàm }
Các biến x cĩ kiểu T và y cĩ kiểu U chỉ mang tính minh họa trong đoạn chƣơng trình trên.
3. Class template (khuơn mẫu hình lớp)
Tƣơng tự nhƣ function template thì class template cũng dùng để tạo ra khuơn mẫu lớp chung cho các kiểu kiểu dữ liệu khác nhau.
Ví dụ: tạo ra lớp PhanSo với tử số và mẫu số là những kiểu dữ liệu khác nhau - Lớp PhanSo cho kiểu dữ liệu số nguyên
- Lớp PhanSo cho kiểu dữ liệu số thực float
- Lớp PhanSo cho kiểu dữ liệu số thực double // PhanSo cho kiểu nguyen
class PS_int { int tuso; int mauso; void Nhap(); void Xuat(); }
// PhanSo cho kiểu số thực class PS_float { float tuso; float mauso; void Nhap(); void Xuat(); }
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 108 Nhƣ vậy trong ví dụ trên, cĩ bao nhiêu kiểu dữ liệu thì chúng ta phải định nghĩa bấy nhiêu lớp cho những cặp kiểu dữ liệu đĩ.
Để cài đặt duy nhất một lần mà cĩ thể sử dụng cho nhiều cặp kiểu dữ liệu khác thì chúng ta sẽ sử dụng class template:
Khai báo khuơn mẫu p:
template <danh sách các tham số> Khai báo lớp
Ví dụ khai báo khuơn mẫu lớp Phân số:
Khi định nghĩa ở ngồi lớp cho các phƣơng thức của lớp thì cú pháp nhƣ sau:
KiểuTrảVề TênLớp<T>:: TênHàm(các tham số) {
//nội dung phƣơng thức }
TỔNG KẾT CHƢƠNG
Việc tham số hĩa cho hàm hay cho lớp sẽ giúp chúng ta chỉ cài đặt một lần với kiểu dữ liệu tổng quát và khi sử dụng, tùy vào kiểu dữ liệu tƣơng ứng thì hàm hay lớp với kiểu dữ liệu đĩ sẽ đƣợc thực thi
// PhanSo cho kiểu số thực double class PS_double { double tuso; double mauso; void Nhap(); void Xuat(); } template <class T> class PhanSo { T tuso; T mauso; void Nhap(); void Xuat(); }
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 109
CÂU HỎI VÀ BÀI TẬP
1. Tác dụng của khuơn mẫu hàm, khuơn mẫu lớp 2. Nêu cú pháp cài đặt khuơn mẫu hàm, khuơn mẫu lớp
3. Viết một khuơn mẫu hàm để tính a*n với a thuộc dữ liệu bất kỳ, n là số nguyên dƣơng
4. Viết hàm tìm min của mảng A[] cĩ kiểu dữ liệu tùy ý. 5. Viết hàm tìm max của mảng A[] cĩ kiểu dữ liệu tùy ý.
6. Viết hàm sắp xếp (tăng, giảm) mảng A[] cĩ kiểu dữ liệu tùy ý.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 110
8. TÀI LIỆU THAM KHẢO
….
[1] Trần Đan Thƣ, Lập trình hƣớng đối tƣợng, Nhà xuất bản khoa học và kỹ thuật, 2010, 370.