Bài 6 : Chương 4 – Lớp ( Class ) Trong C++ Phần 2

1081

Chương 4 – Lớp (Class) Trong C++ Phần 2

Ở bài trươc : Lớp trong c++ phần 1 chúng ta đã tìm hiểu được cơ bản lớp trong c++ bài hôm nay mình và các bạn sẽ đi tìm hiểu tiếp những khúc mắc còn thiếu trong class in C++ :

10. Danh sách khởi tạo thành viên

Có hai cách khởi tạo các thành viên dữ liệu của một lớp. Tiếp cận đầu tiên liên quan đến việc khởi tạo các thành viên dữ liệu thông qua sử dụng các phép gán trong thân của hàm xây dựng. Ví dụ:

Tiếp cận thứ hai sử dụng một danh sách khởi tạo thành viên (member initialization list) trong định nghĩa hàm xây dựng. Ví dụ:

Tác động của khai báo này là width được khởi tạo tới w và height được khởi tạo tới h. Chỉ khác nhau giữa tiếp cận này và tiếp cận trước đó là ở đây các thành viên được khởi tạo trước khi thân của hàm xây dựng được thực hiện.

Danh sách khởi tạo thành viên có thể được sử dụng để khởi tạo bất kỳ thành viên dữ liệu nào của một lớp. Nó luôn được đặt giữa phần đầu và phần thân của hàm xây dựng. Một dấu hai chấm (:) được sử dụng để phân biệt nó với phần đầu. Nó gồm một danh sách các thành viên dữ liệu được phân biệt bằng dấu phẩy (,) mà giá trị khởi tạo của chúng xuất hiện bên trong một cặp dấu ngoặc đơn.

11. Thành viên hằng

Một thành viên dữ liệu của lớp có thể được định nghĩa như hằng. Ví dụ:

Tuy nhiên, các hằng thành viên dữ liệu không thể được khởi tạo bằng cách sử dụng cùng cú pháp như là đối với các hằng khác:

Cách chính xác để khởi tạo một hằng thành viên dữ liệu là thông qua một danh sách khởi tạo thành viên:

Như là một điều được mong đợi, không có hàm thành viên nào được cho phép gán tới một thành viên dữ liệu hằng. Một thành viên dữ liệu hằng không thích hợp cho việc định nghĩa kích thước của một thành viên dữ liệu mảng. Ví dụ trong:

mảng elems sẽ bị bát bỏ bởi trình biên dịch. Lý do là maxCard không được ràng buộc tới một giá trị trong thời gian biên dịch mà được ràng buộc khi chương trình chạy và hàm xây dựng được triệu gọi.

Các hàm thành viên cũng có thể được định nghĩa như là hằng. Điều này được sử dụng để đặc tả các hàm thành viên nào của lớp có thể được triệu gọi cho một đối tượng hằng. Ví dụ:

định nghĩa hàm Member như là một hàm thành viên hằng. Để thực hiện điều đó khóa const được chèn sau phần đầu của hàm ở cả hai bên trong lớp và trong định nghĩa hàm.

Một đối tượng hằng chỉ có thể được sửa đổi bởi các hàm thành viên hằng của lớp:

Luật cho phép một hàm thành viên hằng được cho phép triệu gọi các đối tượng hằng, nhưng nếu nó cố gắng sửa đổi bất kỳ các thành viên dữ liệu nào của lớp là không đúng luật.

Hàm xây dựng và hàm hủy không bao giờ cần được định nghĩa như các thành viên hằng vì chúng có quyền thao tác trên các đối tượng hằng. Chúng cũng không bị tác động bởi luật trên và có thể gán tới một thành viên dữ liệu của một đối tượng hằng trừ phi thành viên dữ liệu chính nó là một hằng.

12. Thành viên tĩnh

Thành viên dữ liệu của một lớp có thể định nghĩa là tĩnh (static). Điều này đảm bảo rằng sẽ có chính xác một bản sao chép của thành viên được chia sẻ bởi tất cả các đối tượng của lớp. Ví dụ, xem xét lớp Window trên một trình bày bản đồ:

Ở đây, không quan tâm đến bao nhiêu đối tượng kiểu Window được định nghĩa, sẽ chỉ là một thể hiện của first. Giống như các biến tĩnh khác, một thành viên dữ liệu tĩnh mặc định được khởi tạo là 0. Nó có thể được khởi tạo tới một giá trị tùy ý trong cùng phạm vi mà định nghĩa hàm thành viên xuất hiện:

Các hàm thành viên cũng có thể được định nghĩa là tĩnh. Về mặc ngữ nghĩa, một hàm thành viên tĩnh giống như là một hàm toàn cục mà là bạn của một lớp nhưng không thể truy xuất bên ngoài lớp. Nó không nhận một đối số ẩn và vì thế không thể tham khảo tới con trỏ this. Các hàm thành viên tĩnh là cần thiết để định nghĩa các thủ tục gọi lại (call-back routines) mà các danh sách tham số của nó được định trước và ngoài phạm vi điều khiển của lập trình viên.

Ví dụ, lớp Window có thể sử dụng một hàm gọi lại để sơn các vùng lộ ra của cửa sổ:

Bởi vì các hàm tĩnh được chia sẻ và không nhờ vào con trỏ this nên chúng được tham khảo tốt nhất nhờ vào sử dụng cú pháp class::member. Ví dụ, first và PaintProc sẽ được tham khảo như Window::first và Window::PaintProc. Các thành viên tĩnh chúng có thể được tham khảo tới thông qua sử dụng cú pháp này bởi các hàm không là thành viên (ví dụ, các hàm toàn cục).

13. Thành viên tham chiếu

Thành viên dữ liệu của lớp có thể được định nghĩa như là tham chiếu. Ví dụ:

Tương tự các hằng thành viên dữ liệu, một tham chiếu thành viên dữ liệu không thể được khởi tạo bằng cách sử dụng cùng cú pháp như đối với các tham chiếu khác:

Cách chính xác để khởi tạo một tham chiếu thành viên dữ liệu là thông qua một danh sách khởi tạo thành viên:

Điều này làm cho widthRef trở thành một tham chiếu cho thành viên width.

14.  Thành viên là đối tượng của một lớp

Thành viên dữ liệu của một lớp có thể là kiểu người dùng định nghĩa, có nghĩa là một đối tượng của một lớp khác. Ví dụ, lớp Rectangle có thể được định nghĩa bằng cách sử dụng hai thành viên dữ liệu Point đại diện cho góc trên bên trái và góc dưới bên phải của hình chữ nhật:

Hàm xây dựng cho lớp Rectangle cũng có thể khởi tạo hai thành viên đối tượng của lớp. Giả sử rằng lớp Point có một hàm xây dựng thì điều này được thực hiện bằng cách thêm topLeft và botRight vào danh sách khởi tạo thành viên của hàm xây dựng cho lớp Rectangle:

Nếu hàm xây dựng của lớp Point không có tham số hoặc nếu nó có các đối số mặc định cho tất cả tham số của nó thì danh sách khởi tạo thành viên ở trên có thể được bỏ qua.

Thứ tự khởi tạo thì luôn là như sau. Trước hết hàm xây dựng cho topLeft được triệu gọi và theo sau là hàm xây dựng cho botRight, và cuối cùng là hàm xây dựng cho chính lớp Rectangle. Hàm hủy đối tượng luôn theo hướng ngược lại. Trước tiên là hàm xây dựng cho lớp Rectangle (nếu có) được triệu gọi, theo sau là hàm hủy cho botRight, và cuối cùng là cho topLeft. Lý do mà topLeft được khởi tạo trước botRight không phải vì nó xuất hiện trước trong danh khởi tạo thành viên mà vì nó xuất hiện trước botRight trong chính lớp đó. Vì thế, định nghĩa hàm xây dựng như sau sẽ không thay đổi thứ tự khởi tạo (hoặc hàm hủy):

15. Mảng các đối tượng

Mảng các kiểu người dùng định nghĩa được định nghĩa và sử dụng nhiều theo cùng phương thức như mảng các kiểu xây dựng sẳn. Ví dụ, hình ngũ giác có thể được định nghĩa như mảng của 5 điểm:

Định nghĩa này giả sử rằng lớp Point có một hàm xây dựng không đối số (nghĩa là một hàm xây dựng có thể được triệu gọi không cần đối số). Hàm xây dựng được áp dụng tới mỗi phần tử của mảng.

Mảng cũng có thể được khởi tạo bằng cách sử dụng bộ khởi tạo mảng thông thường. Mỗi mục trong danh sách khởi tạo có thể triệu gọi hàm xây dựng với các đối số mong muốn. Khi bộ khởi tạo có ít mục hơn kích thước mảng, các phần tử còn lại được khởi tạo bởi hàm xây dựng không đối số. Ví dụ:

khởi tạo bốn phần tử của mảng pentagon tới các điểm cụ thể, và phần tử sau cùng được khởi tạo tới (0,0).

Khi hàm xây dựng có thể được triệu gọi với một đối số đơn, nó vừa đủ để đặc tả đối số. Ví dụ:

là một phiên bản ngắn gọn của:

Mảng các đối tượng cũng có thể được tạo ra động bằng cách sử dụng toán tử new:

Sau cùng, khi mảng được xóa bằng cách sử dụng toán tử delete thì một cặp dấu ngoặc vuông ([])nên được chèn vào:

Nếu không sử dụng cặp [] được chèn vào thì toán tử delete sẽ không có cách nào biết rằng pentagon biểu thị một mảng các điểm chứ không phải là một mảng đơn. Hàm hủy (nếu có) được ứng dụng tới các phần tử của mảng theo thứ tự ngược lại trước khi mảng được xóa. Việc loại bỏ cặp [] sẽ làm cho hàm hủy được áp dụng chỉ tới phần tử đầu tiên của mảng.

Vì các đối tượng của mảng động không thể được khởi tạo rõ ràng ở thời điểm tạo ra, lớp phải có một hàm xây dựng không đối số để điều khiển việc khởi tạo không tường minh. Khi việc khởi tạo không tường minh này không đủ thông tin thì sau đó lập trình viên có thể khởi tạo lại cụ thể cho từng phần tử của mảng:

Mảng các đối tượng động được sử dụng trong các tình huống mà chúng ta không thể biết trước kích thước của mảng. Ví dụ, một lớp đa giác tổng quát không có cách nào biết được một hình đa giác có chính xác bao nhiêu đỉnh:

16. Phạm vi lớp

Một lớp mở đầu phạm vi lớp rất giống với cách một hàm (hay khối) mở đầu một phạm vi cục bộ. Tất cả các thành viên của lớp phụ thuộc vào phạm vi lớp và ẩn đi các thực thể với các tên giống hệt trong phạm vi.Ví dụ trong:

hàm thành viên fork ẩn đi hàm hệ thống toàn cục fork. Hàm thành viên có thể tham khảo tới hàm hệ thống toàn cục bằng cách sử dụng toán tử phạm vi đơn hạng:

Lớp chính nó có thể được định nghĩa ở bất kỳ một trong ba phạm vi có thể:

  • Ở 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ụ:

đị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::

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):

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ụ:

đị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:

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.

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ụ:

đương đương với:

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  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):

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:

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:

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:

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ệ.

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 sau 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.

Các trường header của một gói.

truong-c-2

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 unsignedint:

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

chúng ta có thể viết:

Nguồn : Học lập trình

BÌNH LUẬN

Please enter your comment!
Please enter your name here