Lập trình C++ - Chương 7: Lớp

Chương này giới thiệu cấu trúc lớp C++ để định nghĩa các kiểu dữliệu mới.

Một kiểu dữliệu mới gồm hai thành phần nhưsau:

• Đặc tảcụthểcho các đối tượng của kiểu.

•Tập các thao tác đểthực thi các đối tượng.

 Ngoài các thao tác đã được chỉ định thì không có thao tác nào khác có

thể điều khiển đối tượng. Vềmặt này chúng ta thường nói rằng các thao tác

mô tảkiểu, nghĩa là chúng quyết định cái gì có thểvà cái gì không thểxảy ra

trên các đối tượng. Cũng với cùng lý do này, các kiểu dữliệu thích hợp như

thế được gọi là kiểu dữliệu trừu tượng (abstract data type) - trừu tượng bởi

vì sự đặc tảbên trong của đối tượng được ẩn đi từcác thao tác mà không

thuộc kiểu.

Một định nghĩa lớpgồm hai phần: phần đầu và phần thân. Phần đầu lớp

chỉ định tên lớpvà các lớp cơsở(base class). (Lớp cơsởcó liên quan đến

lớp dẫn xuất và được thảo luận trong chương 8). Phần thân lớp định nghĩa

các thành viên lớp. Hai loại thành viên được hỗtrợ:

• Dữliệu thành viên (member data) có cú pháp của định nghĩa biến và chỉ

định các đại diện cho các đối tượng của lớp.

• Hàm thành viên (member function) có cú pháp của khai báo hàm và chỉ

định các thao tác của lớp (cũng được gọi là các giao diện của lớp).

pdf26 trang | Chuyên mục: C/C++ | Chia sẻ: dkS00TYs | Lượt xem: 1959 | Lượt tải: 1download
Tóm tắt nội dung Lập trình C++ - Chương 7: Lớp, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
 phạm vi toàn cục. Điều này dẫn tới một lớp toàn cục bởi vì nó có thể 
được tham khảo tới bởi tất cả phạm vi khác. Đại đa số các lớp C++ (kể cả 
tất cả các ví dụ được trình bày đến thời điểm này) được định nghĩa ở 
phạm vi toàn cục. 
• Ở phạm vi lớp của lớp khác. Điều này dẫn tới một lớp lồng nhau trong 
đó lớp được chứa đựng bởi lớp khác. 
• Ở phạm vi cục bộ của một khối hay một hàm. Điều này dẫn đến một lớp 
cục bộ trong đó lớp được chứa đựng hoàn toàn bởi một khối hoặc một 
hàm. 
 Lớp lồng nhau là hữu dụng khi một lớp được sử dụng chỉ bởi một lớp 
khác. Ví dụ, 
class Rectangle { // một lớp lồng nhau 
 public: 
 Rectangle (int, int, int, int); 
 //.. 
 private: 
 class Point { 
 public: 
 Point (int, int); 
 private: 
 int x, y; 
 }; 
 Point topLeft, botRight; 
}; 
định nghĩa lớp Point lồng bên trong lớp Rectangle. Các hàm thành viên của lớp 
Point có thể được định nghĩa hoặc nội tuyến (inline) ở bên trong lớp Point hoặc 
ở phạm vi toàn cục. Phạm vi toàn cục sẽ đòi hỏi thêm các tên của hàm thành 
viên bằng cách đặt trước chúng với Rectangle::
Rectangle::Point::Point (int x, int y) 
{ 
 //... 
} 
 Một lớp lồng nhau vẫn còn có thể được truy xuất bên ngoài lớp bao bọc 
của nó bằng cách chỉ định đầy đủ tên lớp. Ví dụ sau là hợp lệ ở bất kỳ phạm 
vi nào (giả sử rằng Point được tạo ra chung (public) ở bên trong Rectangle): 
Rectangle::Point pt(1,1); 
 Lớp cục bộ hữu dụng khi một lớp được sử dụng chỉ bởi một hàm – hàm 
toàn cục hay hàm thành viên – hoặc thậm chí chỉ là một khối. Ví dụ, 
Chương 7: Lớp 113 
void Render (Image &image) 
{ 
 class ColorTable { 
 public: 
 ColorTable (void) { /* ... */ } 
 AddEntry (int r, int g, int b) { /* ... */ } 
 //... 
 }; 
 ColorTable colors; 
 //... 
} 
định nghĩa ColorTable như là một lớp cục bộ tới Render. 
 Không giống như các lớp lồng nhau, một lớp cục bộ không thể truy xuất 
bên ngoài phạm vi nó được định nghĩa. Vì thế hàng sau là không hợp lệ ở 
phạm vi toàn cục: 
ColorTable ct; // không được định nghĩa! 
 Một lớp cục bộ phải được định nghĩa đầy đủ bên trong phạm vi mà nó 
xuất hiện. Vì thế, tất cả các hàm thành viên của nó cần được định nghĩa nội 
tuyến ở bên trong lớp. Điều này ngụ ý rằng một phạm vi cục bộ không phù 
hợp cho định nghĩa bất cứ cái gì ngoại trừ các lớp thật là đơn giản. 
7.17.Cấu trúc và hợp 
Cấu trúc (structure) là tất cả các thành viên của nó được định nghĩa mặc định 
là chung (public). (Nhớ rằng tất cả các thành viên của lớp được định nghĩa 
mặc định là riêng (private)). Các cấu trúc được định nghĩa bằng cách sử dụng 
cùng cú pháp như các lớp ngoại trừ từ khóa struct được sử dụng thay vì class. 
Ví dụ, 
struct Point { 
 Point(int, int); 
 void OffsetPt(int, int); 
 int x, y; 
}; 
đương đương với: 
class Point { 
 public: 
 Point(int, int); 
 void OffsetPt(int, int); 
 int x, y; 
}; 
 Cấu trúc struct được bắt nguồn từ ngôn ngữ C, nó chỉ có thể chứa đựng 
các thành viên dữ liệu. Nó đã được giữ lại cho khả năng tương thích về sau. 
Trong C, một cấu trúc có thể có một bộ khởi tạo với cú pháp tương tự như là 
cú pháp của một mảng. C++ cho phép các bộ khởi tạo như thế dành cho các 
Chương 7: Lớp 114 
cấu trúc và các lớp mà tất cả các thành viên dữ liệu của chúng là chung 
(public): 
class Employee { 
 public: 
 char *name; 
 int age; 
 double salary; 
}; 
Employee emp = {"Jack", 24, 38952.25}; 
Bộ khởi tạo gồm các giá trị được gán cho các thành viên dữ liệu của cấu trúc 
(hoặc lớp) theo thứ tự chúng xuất hiện. Các kiểu khởi tạo này phần lớn được 
thay thế bằng các hàm xây dựng. Vả lại, nó không thể được sử dụng với lớp 
mà có hàm xây dựng. 
 Hợp (union) là một lớp mà tất cả các thành viên dữ liệu của nó được ánh 
xạ tới cùng địa chỉ ở bên trong đối tượng của nó (hơn là liên tiếp như trong 
trường hợp của lớp). Vì thế kích thước đối tượng của một hợp là kích thước 
thành viên dữ liệu lớn nhất của nó. 
 Hợp được sử dụng chủ yếu cho các tình huống mà một đối tượng có thể 
chiếm lấy các giá trị của các kiểu khác nhưng chỉ một giá trị ở một thời điểm. 
Ví dụ, xem xét một trình thông dịch cho một ngôn ngữ lập trình đơn giản 
được gọi là P hỗ trợ cho một số kiểu dữ liệu như là: số nguyên, số thực, 
chuỗi, và danh sách. Một giá trị trong ngôn ngữ lập trình này có thể được 
định nghĩa kiểu: 
union Value { 
 long integer; 
 double real; 
 char *string; 
 Pair list; 
 //... 
}; 
trong đó Pair chính nó là một kiểu người dùng định nghĩa cho việc tạo ra các 
danh sách: 
class Pair { 
 Value *head; 
 Value *tail; 
 //... 
}; 
Giả sử rằng kiểu long là 4 byte, kiểu double là 8 byte, và con trỏ là 4 byte, đối 
tượng thuộc kiểu Value có thể chính xác 8 byte, nghĩa là cùng kích thước với 
kiểu double hay đối tượng kiểu Pair (bằng với hai con trỏ). 
 Một đối tượng trong ngôn ngữ P có thể được biểu diễn bởi lớp, 
class Object { 
 private: 
 enum ObjType {intObj, realObj, strObj, listObj}; 
 ObjType type; // kiểu đối tượng 
 Value val; // giá trị của đối tượng 
 //... 
}; 
trong đó type cung cấp cách thức ghi nhận kiểu của giá trị mà đối tượng giữ 
hiện tại. Ví dụ, khi type được đặt tới strObj, val.string được sử dụng để tham 
khảo tới giá trị của nó. 
 Bởi vì chỉ có một cách duy nhất mà các thành viên dữ liệu được ánh xạ 
tới bộ nhớ nên một hợp không thể có thành viên dữ liệu tĩnh hay thành viên 
dữ liệu mà yêu cầu một hàm xây dựng. 
 Giống như cấu trúc, tất cả các thành viên của hợp được định nghĩa mặc 
định là chung (public). Các từ khóa private, public, và protected có thể được sử 
dụng bên trong struct hoặc union chính xác theo cùng cách mà chúng được sử 
dụng bên trong một lớp để định nghĩa các thành viên riêng, chung, và được 
bảo vệ. 
7.18.Các trường bit 
Đôi khi chúng ta muốn điều khiển trực tiếp một đối tượng ở mức bit sao cho 
nhiều hạng mục dữ liệu riêng có thể được đóng gói thành một dòng bit mà 
không còn lo lắng về các biên của từ hay byte. 
 Ví dụ trong truyền dữ liệu, dữ liệu được truyền theo từng đơn vị rời rạc 
gọi là các gói tin (packets). Ngoài phần dữ liệu cần truyền thì mỗi gói tin còn 
chứa đựng một phần header gồm các thông tin về mạng hỗ trợ cho việc quản 
lý và truyền các gói tin qua mạng. Để làm giảm thiểu chi phí truyền nhận 
chúng ta mong muốn giảm thiểu không gian chiếm bởi phần header. Hình 7.1 
minh họa các trường của header được đóng gói thành các bit gần kề để đạt 
được mục đích này. 
Hình 7.1 Các trường header của một gói. 
type
acknowledge
channel
sequenceNo
moreData 
 Các trường này có thể được biểu diễn thành các thành viên dữ liệu 
trường bit của một lớp Packet. Một trường bit có thể được định nghĩa thuộc 
kiểu int hoặc kiểu unsigned int: 
typedef unsigned int Bit; 
class Packet { 
 Bit type : 2; // rộng 2 bit 
 Bit acknowledge : 1; // rộng 1 bit 
 Bit channel : 4; // rộng 4 bit 
 Bit sequenceNo : 4; // rộng 4 bit 
Chương 7: Lớp 115 
Chương 7: Lớp 116 
 Bit moreData : 1; // rộng 1 bit 
 //... 
}; 
 Một trường bit được tham khảo giống như là tham khảo tới bất kỳ thành 
viên dữ liệu nào khác. Bởi vì một trường bit không nhất thiết bắt đầu trên một 
biến của byte nên việc lấy địa chỉ của nó là không hợp lệ. Với lý do này, một 
trường bit không được định nghĩa là tĩnh (static). 
 Sử dụng bảng liệt kê có thể dễ dàng làm việc với các trường bit hơn. Ví 
dụ, từ bảng liệt kê cho trước 
enum PacketType {dataPack, controlPack, supervisoryPack}; 
enum Bool {false, true}; 
chúng ta có thể viết: 
Packet p; 
p.type = controlPack; 
p.acknowledge = true; 
Bài tập cuối chương 7 
7.1 Giải thích tại sao các tham số của các hàm thành viên Set được khai báo như 
là các tham chiếu. 
7.2 Định nghĩa một lớp có tên là Complex để biểu diễn các số phức. Một số phức 
có hình thức tổng quát là a + bi, trong đó a là phần thực và b là phần ảo ( i 
thay cho ảo). Các quy luật toán học trên số phức như sau: 
 (a + bi) + (c + di) = (a + c) + (b + d)i 
 (a + bi) – (c + di) = (a + c) – (b + d)i 
 (a + bi) * (c + di) = (ac – bd) + (bc + ad)i 
Định nghĩa các thao tác này như là các hàm thành viên của lớp Complex. 
7.3 Định nghĩa một lớp có tên là Menu sử dụng danh sách liên kết của các chuỗi 
để biểu diễn menu với nhiều chọn lựa. Sử dụng một lớp lồng nhau tên là 
Option để biểu diễn tập hợp các phần tử. Định nghĩa một hàm xây dựng, hàm 
hủy, và các hàm thành viên sau cho lớp Menu: 
• Insert chèn một chọn lựa mới vào một vị trí cho trước. Cung cấp một đối 
số mặc định sao cho mục chọn được nối vào ở điểm cuối. 
• Delete xóa một chọn lựa tồn tại. 
• Choose hiển thị menu và mời người dùng chọn một chọn lựa. 
7.4 Định nghĩa lại lớp Set như là một danh sách liên kết sao cho không có giới 
hạn về số lượng các phần tử một tập hợp có thể có. Sử dụng một lớp lồng 
nhau tên là Element để biểu diễn tập hợp các phần tử. 
Chương 7: Lớp 117 
7.5 Định nghĩa một lớp tên là Sequence để lưu trữ các chuỗi đã được sắp xếp. 
Định nghĩa một hàm xây dựng, một hàm hủy, và các hàm thành viên sau cho 
lớp Sequence: 
• Insert chèn một chuỗi mới vào vị trí sắp xếp của nó. 
• Delete xóa một chuỗi hiện có. 
• Find tìm tuần tự với một chuỗi cho trước và trả về true nếu tìm được và 
false nếu không tìm được. 
• Print in ra các chuỗi tuần tự. 
7.6 Định nghĩa lớp tên là BinTree để lưu trữ các chuỗi đã được sắp xếp như là một 
cây nhị phân. Định nghĩa cùng tập các hàm thành viên như đối với lớp 
Sequence ở bài tập trước. 
7.7 Định nghĩa một hàm thành viên cho lớp BinTree để chuyển một chuỗi thành 
cây nhị phân như là bạn của lớp Sequence. Sử dụng hàm này để định nghĩa 
một hàm xây dựng cho lớp BinTree nhận một chuỗi làm đối số. 
7.8 Thêm một thành viên dữ liệu ID là số nguyên vào lớp Menu (Bài tập 7.3) sao 
cho tất cả các đối tượng menu được đánh số tuần tự bắt đầu từ 0. Định nghĩa 
một hàm thành viên nội tuyến trả về số ID. Bạn sẽ theo dõi ID cuối cùng 
được cấp phát như thế nào? 
7.9 Sửa đổi lớp Menu sao cho chọn lựa chính nó có thể là một menu, bằng cách 
ấy cho phép các menu lồng nhau. 

File đính kèm:

  • pdfC++Chuong_07.pdf