CHƢƠNG 2 ĐỐI TƢỢNG VÀ LỚP
2. THIẾT KẾ VÀ CÀI ĐẶT LỚP
2.2. Giao diện và chi tiết cài đặt
Để cài đặt chúng ta sử dụng mơi trƣờng Visual studio C++ 6.0, 2005, 2008, 2010
Sau đây là minh họa giao diện cài đặt Visual studio C++ 2010
Hình 2-2. Mở Microsoft visual C++
Sau đĩ xuất hiện cửa sổ:
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 38
Hình 2-3. Tạo mới một project
Hình 2-4. Cửa sổ đặt tên project
Thực hiện 4 bƣớc nhƣ hình trên bấm OK.
Sau đĩ xuất hiện một cửa sổ, rồi bấm next để tiếp tục. 1:Chọn 2: Chọn Win32 Console Application 4: Đặt tên project 3:Chọn vị trí lƣu project
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 39 Cửa sổ kế tiếp: chọn Empty project rồi bấm finish
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 40
Hình 2-5. Cửa sổ chọn Empty project
Tiếp theo chúng ta sẽ cĩ hai sự lựa chọn để viết code:
Lựa chọn 1: Tất cả chƣơng trình chỉ chứa trong một file cĩ phần mở rộng là
cpp.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 41 kế tiếp làm theo hƣớng dẫn hình sau rồi nhấn nút Add.
Hình 2-6.Thêm file source vào project
Kết quả tạo ra cửa sổ giao diện là nơi chúng ta cĩ thể viết code thực thi: 1: chọn
2: Đặt tên file source
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 42
Hình 2-7. Giao diện soạn thảo
Lựa chọn 2: là cách cài đặt dƣới dạng thƣ viện
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 43 Cửa sổ mới hiện ra:
Sau đĩ bấm Add.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 44
Hình 2-8. Cửa sổ tạo tên lớp
Bấm finish sẽ xuất hiện cửa sổ:
Chọn thẻ Class View:
Chọn Class View
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 45 Click phải vào tên lớp để tiến hành khai báo thuộc tính và phƣơng thức
Hình 2-9. Thêm thuộc tính vào lớp
Kiểu dữ liệu Tên thuộc tính Chọn thuộc tính truy xuất
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 46 Nhấn finish để kết thúc việc thêm một thuộc tính của lớp. Các thuộc tính khác làm tƣơng tự.
Hình 2-10. Cửa sổ khai báo thuộc tính
Khai báo phƣơng thức:
Hình 2-11. Thêm phƣơng thức vào lớp
Hình 2-12. Khai báo phƣơng thức
Tên phƣơng thức Kiểu trả về của hàm Chọn thuộc tính truy xuất Kiểu tham số của hàm Tên tham số
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 47 Nhấn ok rồi lặp lại cho nhiều phƣơng thức khác của lớp
Sau khi tạo xong tất cả thuộc tính và phƣơng thức của lớp chúng ta sẽ cĩ hai file phát sinh. Một file “.cpp” là nơi định nghĩa các phƣơng thức của lớp, cịn một file “.h” là nơi khai báo lớp.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 48
Hình 2-14. Minh họa file .cpp
Cuối cùng chỉ cần thêm vào project một file .cpp, file này chứa hàm main() và là nơi gọi thực thi của các đối tƣợng. Muốn sử dụng lớp đối tƣợng nào thì đầu chƣơng trình chúng ta phải include<file.h> của lớp đĩ.
Nhƣ vậy là đã hồn tất việc tạo giao diện cài đặt. Nhấn Ctrl+F7 để biên dịch
và Ctrl+F5 để chạy chƣơng trình. 2.3. Sử dụng đối tƣợng
Để sử dụng đối tƣợng thì đầu tiên chúng ta tạo ra đối tƣợng bằng câu lệnh khai báo biến, sau đĩ cĩ thể cho đối tƣợng đĩ hoạt động tức gọi các hành động của đối tƣợng đĩ. Hãy nhớ lại rằng ch ng tr nh trong lập trình hƣớng đối tƣợng chính là
sự hoạt động của các đối tƣợng.
Ví dụ
Khai báo nhƣ SinhVien x ; khi đĩ để gọi các phƣơng thức của x chúng ta sử dụng tốn tử chấm “.”, chẳng hạn nhƣ x.XepLoai().
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 49 Đối tƣợng đƣợc sinh ra khi cĩ câu lệnh khai báo biến
Đối tƣợng đƣợc giải thốt khi kết thúc chƣơng trình hoặc khi cĩ lệnh hủy đối tƣợng
2.3.2. Thiết lập và hủy đối tượng.
Phƣơng thức thiết lập (cịn gọi là phƣơng thức khởi tạo).
Khi vừa mới đƣợc tạo ra, bản thân đối tƣợng chƣa cĩ dữ liệu ban đầu. Chúng ta khơng thể kiểm sốt đƣợc các ơ nhớ dành cho các thuộc tính của đối tƣợng đang chứa cái gì? Cĩ thể chỉ là một giá trị rác, một giá trị ngẫu nhiên nào đĩ. Vì vậy rất cần thiết để khởi tạo giá trị ban đầu cho đối tƣợng.
Để khởi tạo giá trị ban đầu cho đối tƣợng chúng ta sử dụng phƣơng thức khởi tạo.
Đặc điểm:
- Cĩ tên trùng với tên lớp - Khơng kiểu trả về
- Cĩ thể cĩ nhiều phƣơng thức khởi tạo (các phƣơng thức này đƣợc phân biệt nhờ danh sách tham số truyền vào)
- Khơng cần cĩ câu lệnh gọi mà đƣợc tự động thực thi khi đối tƣợng vừa đƣợc tạo ra.
Ví dụ: hai phƣơng thức nhƣ hình sau đƣợc gọi là các phƣơng thức khởi tạo của
lớp PhanSo.
Phân loại: Cĩ 3 loại phƣơng thức khởi tạo đĩ là phƣơng thức khởi tạo mặc
định, phƣơng thức khởi tạo cĩ tham số và phƣơng thức khởi tạo sao chép.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 50 Là phƣơng thức khởi tạo khơng nhận tham số đầu vào, nội dung của phƣơng thức là gán giá trị mặc định cho các thuộc tính của lớp đối tƣợng.
Cú pháp:
TênLớp() {
//cĩ thể gán giá trị hằng cho thành phần dữ liệu của lớp ở đây } Ví dụ nhƣ: PhanSo() { ts=0; ms=0; }
Phƣơng thức khởi tạo sẽ đƣợc gọi khi cĩ câu lệnh khai báo: PhanSo a;
Nhƣ vậy sau câu lệnh này thì đối tƣợng a sẽ đƣợc khởi gán giá trị ban đầu là phân số cĩ tử là 0 và mẫu là 1.
Phƣơng thức khởi tạo cĩ tham số
Là phƣơng thức khởi tạo nhận tham số đầu vào từ bên ngồi, nội dung của phƣơng thức là lấy giá trị truyền vào để gán cho các thuộc tính của đối tƣợng.
Cú pháp:
TênLớp(danh sách tham số) {
// gán giá trị cho thành phần dữ liệu của lớp ở đây } Ví dụ nhƣ: PhanSo(int t, int m){ ts=t; ms=t; }
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 51 Phƣơng thức khởi tạo này sẽ đƣợc gọi khi cĩ câu lệnh khai báo ví dụ nhƣ: PhanSo a(2,3);
Sau khi khai báo đối tƣợng a nhƣ trên thì đối tƣợng a vừa đƣợc cấp phát vùng nhớ vừa đƣợc khởi gán giá trị ban đầu là phân số 2/3.
Phƣơng thức khởi tạo sao chép
Ngồi cách khởi tạo bằng phƣơng thức khởi tạo mặc định và phƣơng thức khởi tạo cĩ tham số nhƣ trên chúng ta cịn cĩ thể khởi tạo một đối tƣợng thơng qua một đối tƣợng đã cĩ.
Ví dụ:
Đối tƣợng d đƣợc khởi tạo dựa trên đối tƣợng c – là đối tƣợng đã tạo ra trƣớc đĩ. Quan sát kỹ ví dụ trên, mặc dù chúng ta chƣa định nghĩa và cài đặt phƣơng thức khởi tạo sao chép cho lớp đối tƣợng PhanSo nhƣng câu lệnh vẫn đƣợc thực hiện và cho kết quả nhƣ mong muốn.
Thật vậy, trong ngơn ngữ C++, phƣơng thức khởi tạo sao chép đƣợc trình biên dịch cung cấp mặc định cho các lớp đối tƣợng do ngƣời dùng định nghĩa, đƣợc gọi là phương thức khởi tạo sao chép mặc đinh (default copy contructor). Phƣơng
thức này để sao chép tồn từng thành phần thuộc tính của đối tƣợng nguồn sang đối tƣợng đích.
Ngồi cách sao chép nhƣ ví dụ trên chúng ta cịn cĩ thể yêu cầu sao chép bằng cách khác nhƣ PhanSo a=c. Phƣơng thức khởi tạo sao chép của một lớp cịn đƣợc
gọi khi chúng ta truyền hoặc nhận giá trị trả về đối tƣợng của lớp đĩ theo kiểu tham trị.
Tuy nhiên trong quá trình sao chép là sao chép từng thành phần theo dạng từng bit, nếu các thành phần dữ liệu là kiểu con trỏ thì quá trình sao chép sẽ chỉ sao chép giá trị của con trỏ chứ khơng thật sự sao chép vùng nhớ mà chúng quản lý. Trong trƣờng hợp này nếu chúng ta chỉ sử dụng phƣơng thức khởi tạo sao chép mặc định mà trình biên dịch cấp thì sẽ xảy ra những hiệu ứng lề khơng mong muốn.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 52 Từ ví dụ trên ta thấy hai đối tƣợng c, d cĩ thuộc tính tu cùng trỏ vào một ơ nhớ, điều này dẫn đến những hiệu ứng lề khơng mong muốn.
Nhƣ vậy trong trƣờng hợp này, tức trong trƣờng hợp thành phần dữ liệu của lớp đối tƣợng cĩ các biến con trỏ và chúng đang quản lý các vùng nhớ đƣợc cấp phát động, nếu cĩ nhu cầu sao chép các đối tƣợng dạng này, ngƣời lập trình phải viết lại phƣơng thức khởi tạo sao chép để việc sao chép đƣợc tiến hành chính xác và khơng bị hiệu ứng lề nhƣ ví dụ trên nữa.
Cú pháp của phƣơng thức khởi tạo sao chép:
<Tênlớp>(const <Tênlớp> &<ĐốiTƣợngNguồn>) {
//cấp phát vùng nhớ cho thuộc tính đích sau đĩ sao chép giá trị. }
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 53 Tĩm lại, một cách đơn giản, bình thƣờng nếu kiểu dữ liệu của các thành phần dữ liệu (thuộc tính) bên trong một lớp đối tƣợng khơng phải là kiểu dữ liệu con trỏ thì chúng ta khơng cần phải cài đặt phƣơng thức tạo lập sao chép cho lớp, bởi khi đĩ sử dụng phƣơng thức khởi tạo sao chép mặc định của trình biên dịch là đủ.
Phƣơng thức hủy
Dọn dẹp thơng tin bên trong đối tƣợng trƣớc khi hủy
Tƣơng tự nhƣ vấn đề khởi tạo cấu trúc bên trong đối tƣợng, vấn đề dọn dẹp thơng tin bên trong đối tƣợng trƣớc khi hủy cũng là một vấn đề rất quan trọng mà ngƣời lập trình cần phải nắm rõ. Một khi đối tƣợng khơng cịn đƣợc sử dụng nữa, các tài nguyên đã đƣợc cấp phát cho đối tƣợng cĩ thể trở thành rác, bởi vì những tài nguyên đƣợc cấp phát động chỉ bị hủy khi cĩ câu lệnh hủy chứ khơng đƣợc tự động hủy bởi trình biên dịch khi hết phạm vi hoạt động. Trong lập trình hƣớng đối tƣợng, phƣơng thức hủy (destructor) sẽ đảm nhận nhiệm vụ này. Phƣơng thức hủy đƣợc gọi mặc định ngay khi đối tƣợng kết thúc phạm vi sử dụng để hủy vùng nhớ dành cho đối tƣợng, thu hồi tồn bộ tài nguyên đã cấp phát cho đối tƣợng trong quá trình sống của đối tƣợng.
Việc dọn dẹp thơng tin bên trong đối tƣợng trƣớc khi hủy giúp tránh xảy ra những tình huống khơng mong muốn, chẳng hạn nhƣ trƣờng hợp rị rỉ bộ nhớ:
Chƣơng trình chạy một lát thì khơng chạy nữa do hết bộ nhớ
Khi chƣơng trình đang chạy, các phần mềm khác khơng chạy đƣợc nữa do đã bị chƣơng trình của chúng ta giành hết bộ nhớ, chỉ khi đĩng chƣơng trình thì các phần mềm khác mới chạy đƣợc.
Sau khi chƣơng trình của chúng ta chạy xong thì máy bị treo, phải khởi động lại máy.
Đặc điểm của phƣơng thức hủy
Phƣơng thức hủy trong C++ cĩ những đặc điểm quan trọng sau: Cĩ tên trùng tên lớp, cĩ dấu ~ đặt ngay phía trƣớc
Khơng cĩ giá trị trả về Khơng cĩ tham số đầu vào
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 54 Phƣơng thức hủy sẽ đƣợc tự động gọi khi đối tƣợng của lớp hết phạm vi
sử dụng
Do vậy, trong trƣờng hợp lớp đối tƣợng khơng sử dụng các vùng nhớ cấp phát động thì ngƣời sử dụng khơng cần phải xây dựng phƣơng thức hủy, khi đo chỉ cần sử dụng phƣơng thức hủy mặc định của trình biên dịch là đủ.
Cách cài đặt và ví dụ
Cú pháp cài đặt phƣơng thức hủy:
~Tênlớp() {
//nội dung hủy }
Ví dụ với lớp phân số mà cĩ thuộc tính tu là con trỏ đã xét ở trên, trong trƣờng hợp này chúng ta phải xây dựng phƣơng thức hủy cho đối tƣợng.
~PhanSo() {
delete tu;
}
2.4. Con trỏ this
Khi một hàm thành viên tham chiếu thành viên khác của lớp cho đối tƣợng cụ thể của lớp đĩ, làm thế nào C++ bảo đảm rằng đối tƣợng thích hợp đƣợc tham chiếu? Câu trả lời là mỗi đối tƣợng duy trì một con trỏ trỏ tới chính nĩ – gọi là con trỏ this – Đĩ là một tham số ẩn trong tất cả các tham chiếu tới các thành viên bên trong đối tƣợng đĩ. Con trỏ this cũng cĩ thể đƣợc sử dụng tƣờng minh. Mỗi đối tƣợng cĩ thể xác định địa chỉ của chính mình bằng cách sử dụng từ khĩa this.
Con trỏ this đƣợc sử dụng để tham chiếu cả các thành viên dữ liệu và hàm thành viên của một đối tƣợng. Kiểu của con trỏ this phụ thuộc vào kiểu của đối tƣợng.
Tĩm lại, con trỏ this là đại diện cho đối tƣợng hiện hành, đối tƣợng hiện hành là đối tƣợng đang yêu cầu phƣơng thức đĩ thực hiện.
Ví dụ một phƣơng thức tính tổng hai phân số của lớp PhanSo sẽ đƣợc viết nhƣ sau:
PhanSo TongPS(PhanSo x) {
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 55 tong.tu = thistu * x.mau + x.tu*thismau;
tong.mau = thismau * x.mau; return tong;
}
Giả sử ta cĩ hai phân số x, y. Muốn tính tổng x và y chúng ta gọi y.TongPS(x). Nhƣ vậy phƣơng thức TongPS() sẽ đƣợc gọi thực thi và nhiệm vụ là tính tổng của x và y. Do đĩ con trỏ this trong trƣờng hợp này chính là y – là đối tƣợng hiện hành.
2.5. Con trỏ đối tƣợng
Khai báo sử dụng con trỏ đối tƣợng. SinhVien *p;
p= new SinhVien;
Để gọi các phƣơng thức của đối tƣợng p thì sử dụng tốn tử “”, chẳng hạn nhƣ pXepLoai().
Lƣu ý khi nào khơng sử dụng nữa thì nhớ hủy vùng nhớ đã cấp phát cho p bằng câu lệnh delete p;
Khi cấp phát bằng tốn tử new thì phƣơng thức khởi tạo của lớp sẽ đƣợc gọi và khi hủy đối tƣợng bằng tốn tử delete thì phƣơng thức hủy của lớp sẽ đƣợc gọi.
2.6. Đối tƣợng thành phần
Khái niệm
Một đối tƣợng lại là một thành phần thuộc tính của một lớp khác, đối tƣợng này gọi là đối tƣợng thành phần. Lớp cĩ đối tƣợng thành phần đƣợc gọi là lớp bao.
Cách xây dựng phương thức khởi tạo cho lớp bao
Cú pháp:
TenLopBao(DS cac tham so):DTThanhPhan1,DTThanhPhan2,.. {
// khởi tạo cho các thuộc tính cịn lại khơng phải là đối tƣợng thành phần
}
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 56
Truy xuất thành phần của đối tượng thành phần
Việc truy xuất đến thuộc tính (đối tƣợng thành phần) trong lớp bao theo quy tắc sau:
- Khơng thể nào truy xuất đƣợc thành phần private của đối tƣợng thành
phần trong lớp bao
- Đƣợc phép truy xuất đến thành phần public của đối tƣợng thành phần
trong lớp bao
2.7. Thành phần static
2.7.1. Ý nghĩa.
Trong một số trƣờng hợp, chúng ta cĩ nhu cầu sử dụng một biến là thành phần dữ liệu chung cho tất cả các đối tƣợng. Tuy nhiên, trong trƣờng hợp này, nếu sử dụng biến tồn cục cho cả chƣơng trình sẽ gây ra các nguy cơ nhất định và về mặt ngữ nghĩa sử dụng biến tồn cục cũng khơng hợp lý.
2.7.2. Dữ liệu static.
Để giải quyết vấn đề trên, ngơn ngữ C++ cho phép ngƣời lập trình sử dụng thành phần dữ liệu tĩnh (static data member). Thành phần dữ liệu tĩnh là thành phần chung của lớp đối tƣợng tƣơng ứng. Thành phần này khơng thuộc vào một đối tƣợng cụ thể nào cả mà nĩ là một thành phần chung cho tất cả các đối tƣợng của lớp tƣơng ứng.
Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 57 Cú pháp khai báo dữ liệu tĩnh:
static KiểuDữLiệu TênBiến;
ví dụ:
2.7.3. Hàm static.
Tƣơng tự, trong trƣờng hợp một số phƣơng thức của lớp khi sử dụng lại khơng cần một đối tƣợng cụ thể nào đĩ, chúng ta cũng cĩ thể khai báo chúng là các phƣơng thức tĩnh của lớp (static method).
Cú pháp khai báo phƣơng thức tĩnh:
static KDLTrảVề TênPhƣơngThức (DSThamSố);
Khi cài đặt, chúng ta khơng cần viết lại từ khĩa static
Ví dụ về quản lý các hĩa đơn bán hàng, mỗi hĩa đơn cĩ thuộc tính riêng là
tên hàng và số tiền. Vậy nếu quan tâm đến tổng số hĩa đơn đ đƣợc bán và tổng