Trong bài trước  – Chuyển đổi kiểu ngầm định (ép buộc), chúng ta đã thảo luận rằng trình biên dịch có thể chuyển đổi ngầm một giá trị từ kiểu dữ liệu này sang kiểu dữ liệu khác thông qua một hệ thống gọi là chuyển đổi kiểu ngầm định. Khi bạn muốn quảng bá giá trị từ một kiểu dữ liệu này sang kiểu dữ liệu tương tự lớn hơn, sử dụng chuyển đổi kiểu ngầm định là tốt.

Tuy nhiên, nhiều lập trình viên mới thử một cái gì đó như sau: float f = 10/4 ;. Tuy nhiên, vì 10 và 4 đều là số nguyên nên không có khuyến mãi nào diễn ra. Phép chia số nguyên được thực hiện vào ngày 10/4, dẫn đến giá trị là 2, giá trị này sau đó được chuyển đổi ngầm thành 2.0 và được gán cho biến f!

Trong trường hợp bạn đang sử dụng giá trị chữ (chẳng hạn như 10 hoặc 4), việc thay thế một hoặc cả hai giá trị chữ nguyên bằng giá trị chữ dấu phẩy động (10.0 hoặc 4.0) sẽ khiến cả hai toán hạng được chuyển đổi thành giá trị dấu chấm động, và phép chia sẽ được thực hiện bằng phép toán dấu phẩy động (và do đó giữ lại thành phần phân số).

Nhưng nếu bạn đang sử dụng các biến thì sao? Hãy xem xét trường hợp này:

int i1 { 10 };
int i2 { 4 };
float f(i1 / i2); // List initialization would prevent this. Direct initialization is used for demonstration only.

Biến f sẽ có giá trị là 2. Làm thế nào để chúng ta nói với trình biên dịch rằng chúng ta muốn sử dụng phép chia dấu phẩy động thay vì phép chia số nguyên? Câu trả lời là sử dụng toán tử ép kiểu (thường được gọi là ép kiểu) để yêu cầu trình biên dịch thực hiện chuyển đổi kiểu rõ ràng. Một phép ép kiểu đại diện cho một yêu cầu của người lập trình để thực hiện một chuyển đổi kiểu rõ ràng.

1. Kiểu casting

Trong C ++, có 5 loại casts khác nhau: C-style casts, static casts, const casts, dynamic cast và reinterpretation. Bốn cái sau đôi khi được gọi là casts được đặt tên.

Chúng ta sẽ đề cập đến casts kiểu C và casts tĩnh trong bài học này. Các casts động mà chúng tôi sẽ lưu cho đến sau khi chúng tôi đề cập đến các con trỏ và kế thừa trong các bài học trong tương lai.

Thường nên tránh sử dụng các casts Const và diễn giải lại các casts vì chúng chỉ hữu ích trong một số trường hợp hiếm hoi và có thể gây hại nếu sử dụng không đúng cách.

Lưu ý

Tránh sử dụng const cast và diễn giải lại cast trừ khi bạn có lý do chính đáng để sử dụng chúng.

2. casts kiểu C

Trong lập trình C chuẩn, ép kiểu được thực hiện thông qua toán tử (), với tên của kiểu để chuyển đổi giá trị được đặt bên trong dấu ngoặc. Ví dụ:

int i1 { 10 };
int i2 { 4 };
float f { (float)i1 / i2 };

Trong chương trình trên, chúng ta sử dụng kiểu ép kiểu float C để yêu cầu trình biên dịch chuyển i1 thành giá trị dấu phẩy động. Vì toán hạng bên trái của toán tử / bây giờ được đánh giá thành giá trị dấu phẩy động, nên toán tử bên phải cũng sẽ được chuyển đổi thành giá trị dấu phẩy động và phép chia sẽ được thực hiện bằng phép chia dấu phẩy động thay vì phép chia số nguyên!

C ++ cũng sẽ cho phép bạn sử dụng kiểu ép kiểu C với cú pháp gọi hàm giống như cú pháp:

int i1 { 10 };
int i2 { 4 };
float f { float(i1) / i2 };

Điều này thực hiện giống với ví dụ trước.

Mặc dù dàn diễn viên kiểu C có vẻ là một dàn diễn viên duy nhất, nhưng nó thực sự có thể thực hiện nhiều loại chuyển đổi khác nhau tùy thuộc vào ngữ cảnh. Điều này có thể bao gồm ép kiểu tĩnh, ép kiểu const hoặc ép kiểu diễn giải lại (hai kiểu sau mà chúng tôi đã đề cập ở trên mà bạn nên tránh). Do đó, các casts kiểu C có nguy cơ vô tình bị lạm dụng và không tạo ra hành vi như mong đợi, một điều có thể dễ dàng tránh được bằng cách sử dụng các casts C ++ thay thế.

Như một bên …

Nếu bạn tò mò, bài viết này có thêm thông tin về cách thức hoạt động của casts kiểu C.

Lưu ý: Tránh sử dụng casts kiểu C.

3. static_cast

C ++ giới thiệu một toán tử ép kiểu được gọi là static_cast, có thể được sử dụng để chuyển đổi giá trị của một kiểu thành giá trị của kiểu khác.

Trước đây, bạn đã thấy static_cast được sử dụng để chuyển đổi một char thành một int để std :: cout in nó dưới dạng một số nguyên thay vì một char:

char c { 'a' };
std::cout << c << ' ' << static_cast<int>(c) << '\n'; // prints a 97

Toán tử static_cast nhận một giá trị duy nhất làm đầu vào và xuất ra cùng một giá trị được chuyển đổi thành kiểu được chỉ định bên trong dấu ngoặc nhọn. Static_cast được sử dụng tốt nhất để chuyển đổi một loại cơ bản thành một loại khác.

int i1 { 10 };
int i2 { 4 };
 
// convert an int to a float so we get floating point division rather than integer division
float f { static_cast<float>(i1) / i2 }; 

Ưu điểm chính của static_cast là nó cung cấp tính năng kiểm tra kiểu thời gian biên dịch, giúp khó tạo ra lỗi vô ý hơn. Static_cast cũng (có chủ đích) kém mạnh hơn các casts kiểu C, vì vậy bạn không thể vô tình loại bỏ const hoặc làm những việc khác mà bạn có thể không định làm.

Bạn nên

Ủng hộ static_cast khi bạn cần chuyển đổi giá trị từ loại này sang loại khác

4. Sử dụng casts để làm rõ ràng các chuyển đổi kiểu ngầm

Các trình biên dịch thường sẽ phàn nàn khi thực hiện chuyển đổi kiểu ngầm định không an toàn. Ví dụ, hãy xem xét chương trình sau:

int i { 48 };
char ch = i; // implicit conversion

Truyền một int (4 byte) sang một char (1 byte) có khả năng không an toàn (vì trình biên dịch không thể biết liệu số nguyên có làm tràn phạm vi của char hay không) và do đó, trình biên dịch thường sẽ in cảnh báo. Nếu chúng ta sử dụng khởi tạo danh sách, trình biên dịch sẽ gây ra lỗi.

Để giải quyết vấn đề này, chúng ta có thể sử dụng một cast tĩnh để chuyển đổi rõ ràng số nguyên của chúng ta thành một char:

int i { 48 };
 
// explicit conversion from int to char, so that a char is assigned to variable ch
char ch { static_cast<char>(i) };

Khi chúng tôi làm điều này, chúng ta sẽ nói rõ ràng với trình biên dịch rằng chuyển đổi này là nhằm mục đích và chúng ta chấp nhận trách nhiệm về hậu quả (ví dụ: làm tràn phạm vi của một ký tự nếu điều đó xảy ra). Vì đầu ra của static_cast này là kiểu char, việc gán cho biến ch không tạo ra bất kỳ kiểu không khớp nào và do đó không có cảnh báo.

Trong chương trình sau, trình biên dịch thường sẽ phàn nàn rằng việc chuyển đổi double thành int có thể dẫn đến mất dữ liệu:

int i { 100 };
i = i / 2.5;

Để nói với trình biên dịch rằng chúng tôi muốn làm điều này một cách rõ ràng:

int i { 100 };
i = static_cast<int>(i / 2.5);

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Nguồn và Tài liệu tiếng anh tham khảo:

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!