Đa năng hóa toán tử-toán tử và dấu phẩy
Toán tử dấu phẩy là toán tử hai ngôi. Chúng ta có thể đa năng hóa toán tử dấu phẩy có ý nghĩa tùy thích. Tuy nhiên, nếu muốn đa năng hóa toán tử phẩy có ý nghĩa tương tự như toán tử phẩy bình thường, chúng ta cần bỏ qua toán hạng bên trái dấu ...
Toán tử dấu phẩy là toán tử hai ngôi. Chúng ta có thể đa năng hóa toán tử dấu phẩy có ý nghĩa tùy thích. Tuy nhiên, nếu muốn đa năng hóa toán tử phẩy có ý nghĩa tương tự như toán tử phẩy bình thường, chúng ta cần bỏ qua toán hạng bên trái dấu phẩy (nghĩa là đối tượng mà qua đó hàm toán tử tương ứng được gọi) và trả về đối tượng bên phải dấu phải như là kết quả của toán tử. Do vậy trong một danh sách gồm các biểu thức được ngăn cách bởi các dấu phẩy, mọi toán hạng trừ toán hạng ngoài cùng bên phải đều bị bỏ qua.
Ví dụ 4.10: Đa năng hóa toán tử dấu phẩy.
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 4.10, kết quả ở hình 4.15
![](/pictures/picfullsizes/2018/05/24/uir1527153411.jpg)
Hình 4.15: Kết quả của ví dụ 4.10
Toán tử dấu mũi tên -> (hoặc toán tử con trỏ cấu trúc) cho phép chúng ta truy cập thành viên của đối tượng thuộc class, struct và union khi được áp dụng vào con trỏ chỉ đến đối tượng đó. Chúng ta có thể đa năng hóa toán tử này, hàm toán tử của toán tử -> phải là hàm thành viên của lớp. Nếu toán tử -> có dạng a-> thì hàm toán tử là a.operator->()
Ví dụ 4.11: Đa năng hóa toán tử ->.
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 4.11, kết quả ở hình 4.16
![](/pictures/picfullsizes/2018/05/24/xxa1527153412.jpg)
Hình 4.16: Kết quả của ví dụ 4.11
Khi đa năng hóa toán tử ->, C++ quy định hàm toán tử của nó phải trả về:
Hoặc là con trỏ trỏ đến đối tượng thuộc lớp chứa thành viên dữ liệu cần truy cập (lớp mà trong đó hàm toán tử được định nghĩa). Một toán tử -> bình thường sẽ được trình biên dịch tự động áp dụng vào con trỏ ấy để truy cập thành viên dữ liệu đó của đối tượng.
Hoặc là đối tượng thuộc lớp khác. Lớp này phải chứa định nghĩa hàm toán tử. Trình biên dịch sẽ tự động áp dụng toán tử -> trên đối tượng được trả về.Kết quả thu được có thể là một con trỏ trỏ đến đối tượng hoặc một đối tượng. Cứ thế, chúng ta có sự diễn dịch theo lối đệ quy cho tới khi nào kết quả là một con trỏ trỏ đến đối tượng thuộc lớp chứa thành viên dữ liệu cần truy cập.
Ví dụ 4.12: Minh họa quá trình diễn dịch đệ quy khi đa năng hóa toán tử ->.
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 4.12, kết quả ở hình 4.17
![](/pictures/picfullsizes/2018/05/24/eiq1527153412.jpg)
Hình 4.17: Kết quả của ví dụ 4.12
Chúng ta có thể đa năng hóa toán tử gán (=) nhưng hàm toán tử của nó phải là hàm thành viên của lớp. Nếu toán tử gán có dạng a=b thì hàm toán tử có dạng a.operator(b).
Ví dụ 4.13: Đa năng hóa toán tử gán.
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 4.13, kết quả ở hình 4.18
![](/pictures/picfullsizes/2018/05/24/csh1527153412.jpg)
Hình 4.18: Kết quả của ví dụ 4.13
Phần lớn các chương trình xử lý thông tin sự đa dạng của các kiểu. Đôi khi tất cả các thao tác "dừng lại bên trong một kiểu". Chẳng hạn, một số nguyên với một số nguyên tạo thành một số nguyên (miễn là kết quả không quá lớn để được biểu diễn như một số nguyên). Nhưng thật cần thiết để chuyển đổi dữ liệu của một kiểu tới dữ liệu của kiểu khác. Điều này có thể xảy ra trong các phép gán, các kết quả tính toán, trong việc chuyển các giá trị tới hàm, và trong việc trả về trị từ hàm. Trình biên dịch biết làm thế nào để thực hiện các chuyển đổi nào đó trong số các kiểu có sẵn. Các lập trình viên có thể ép buộc các chuyển đổi trong số các kiểu có sẵn bởi ép kiểu.
Nhưng đối với các kiểu do người dùng định nghĩa thì trình biên dịch không thể tự động biết làm thế nào chuyển đổi trong số các kiểu dữ liệu do người dùng định nghĩa và các kiểu có sẵn. Lập trình viên phải chỉ rõ làm sao các chuyển đổi như vậy sẽ xuất hiện. Các chuyển đổi như thế có thể được thực hiện với constructor chuyển đổi.
Một toán tử chuyển đổi kiểu có thể được sử dụng để chuyển đổi một đối tượng của một lớp thành đối tượng của một lớp khác hoặc thành một đối tượng của một kiểu có sẵn. Toán tử chuyển đổi kiểu như thế phải là hàm thành viên không tĩnh và không là hàm friend. Prototype của hàm thành viên này có cú pháp:
operator <data type> ();
Ví dụ 4.14: Toán tử chuyển đổi kiểu
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 4.14, kết quả ở hình 4.19
![](/pictures/picfullsizes/2018/05/24/ybg1527153412.jpg)
Hình 4.19: Kết quả của ví dụ 4.14
Các toán tử new và delete toàn cục có thể được đa năng hóa. Điều này cho phép các lập trình viên C++ có khả năng xây dựng một hệ thống cấp phát bộ nhớ theo ý người dùng, cói cùng giao tiếp như hệ thống cấp phát mặc định.
Có hai cách đa năng hóa các toán tử new và delete:
Chúng ta có thể đa năng hóa một cách toàn cục nghĩa là thay thế hẳn các toán tử new và delete mặc định.
Chúng ta năng hóa các toán tử new và delete với tư cách là hàm thành viên của lớp nếu muốn các toán tử new và delete áp dụng đối với lớp đó. Khi chúng ta dùng new và delete đối với lớp nào đó, trình biên dịch sẽ kiểm tra xem new và delete có được định nghĩa riêng cho lớp đó hay không; nếu không thì dùng new và delete toàn cục (có thể đã được đa năng hóa).
Hàm toán tử của toán tử new và delete có prototype như sau:
void * operator new(size_t size );
void operator delete(void * ptr );
Trong đó tham số kiểu size_t được trình biên dịch hiểu là kích thước của kiểu dữ liệu được trao cho toán tử new.
Đa năng hóa toán tử new và delete toàn cục:
Ví dụ 4.15: Đa năng hóa toán tử new và delete toàn cục đồng thời chứng tỏ rằng toán tử new và delete do đa năng hóa thay thế toán tử new và delete mặc định.
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 4.15, kết quả ở hình 4.20
![](/pictures/picfullsizes/2018/05/24/usc1527153413.jpg)
Hình 4.20: Kết quả của ví dụ 4.15
Đa năng hóa toán tử new và delete cho một lớp:
Nếu muốn toán tử new và delete có tính chất đặc biệt chỉ khi áp dụng cho đối tượng của lớp nào đó, chúng ta có thể đa năng hóa toán tử new và delete với tư cách là hàm thành viên của lớp đó. Việc này không khác lắm so với cách đa năng hóa toán tử new và delete một cách toàn cục.
Ví dụ 4.16: Đa năng hóa toán tử new và delete cho một lớp.
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 4.16, kết quả ở hình 4.21
![](/pictures/picfullsizes/2018/05/24/bfj1527153413.jpg)
Hình 4.21: Kết quả của ví dụ 4.16