Chuyển đổi thông qua constructor
Mặc định C++ sẽ hiểu bất kì 1 constructor nào cũng là toán tử ngầm định (implicit operator), bài học này chúng ta sẽ tìm hiểu thêm về nó nhé!
constructor is implicit operator
Chúng ta cùng xem ví dụ sau về class PhanSo:
Kết quả chương trình là: 2/1
Có thể thấy chúng ta đã gán ps
cho số 2
chứ không phải là 1 phân số nhưng kết quả chúng ta vẫn nhận được 1 phân số. Giải thích cho điều này, C++ đã tìm thấy 1 constructor của chúng ta có tham số kiểu int nên đã cố gắng chuyển đổi ngầm định (implicitly convert) số 2 sang kiểu PhanSo nên kết quả chương trình vẫn chạy bình thường.
Từ khóa explicit
Việc ép kiểu ngầm định như ở trên cũng gây ra 1 số nguy hiểm, trường hợp dưới đây là ví dụ:
Kết quả chương trình: wrong step!
Chúng ta thấy C++ đã chuyển đổi “nhầm” chữ z sang constructor có tham số int. Vì sao vậy? Trong khi chúng ta cũng đã có 1 constructor kiểu char*
tại sao lại không chuyển đổi bằng constructor này, đó là vì kí tự (char) là 1 phần của họ số nguyên vì vậy trình biên dịch đã chuyển nó sang cho constructor version số nguyên kết quả là iData
không có gì cả (ngoài mong muốn của chúng ta).
Để giải quyết vấn đề trên, chúng ta sẽ làm cho các constructor (và các hàm chuyển đổi) được rõ ràng hơn thông qua từ khóa explicit
. Constructor (và hàm chuyển đổi) với từ khóa này sẽ không thể sử dụng cho chuyển đổi ngầm định hay sao chép khởi tạo. Cùng quay lại chương trình trên với từ khóa explicit
:
Lúc này chúng ta sẽ thấy chương trình báo lỗi nhưng nó là kết quả đúng :) Vì sao? Vì nếu trình biên dịch còn nhận constructor có tham số int thì chương trình sẽ chạy bình thường nhưng không có kết quả chúng ta mong muốn, còn nếu chương trình không nhận constructor có tham số kiểu int nó sẽ không tìm thấy constructor nào thích hợp để chuyển đổi kiểu char
sang kiểu iString
(chúng ta còn 1 constructor có tham số kiểu char*
nhưng mặc định không thể chuyển từ char
sang char*
được nên không thể dùng constructor này). Vậy từ khóa explicit
đã hoạt động tốt.
Để chuyển đối được theo mong muốn (trong ví dụ trên mong muốn chuyển được kiểu char
sang iString
) chúng ta có thể tạo thêm 1 constructor có tham số kiểu char. Ngược lại nếu hoàn toàn không muốn xảy ra việc chuyển đổi này hãy đặt constructor có tham số kiểu char ở phạm vi private (nhưng vẫn có thể truy cập được từ bên trong class do đặc tính của truy xuất private).
Từ khóa delete
Ví dụ mình không muốn lớp iString của mình nhận kiểu char, đơn giản mình sẽ không viết constructor hoặc bất cứ hàm chuyển đổi nào cho kiểu char hoặc cách mình vừa nêu ở trên nhưng trong trường hợp nào đó mà bạn vẫn nghi ngờ có sự chuyển đổi này chúng ta có thể chắc chắn hơn bằng cách dùng từ khóa delete
.
Chúng ta có thể dùng từ khóa delete
cho copy constructor hoặc các cài đặt toán tử (overload operator) mà chúng ta không mong muốn được sử dụng.
Tổng kết
Chúng ta đã hiểu hơn về constructor và tìm hiểu được 2 từ khóa mới là explicit
và delete
. Có thắc mắc các bạn bình luận bên dưới để tụi minh giải đáp nhé. Pie~