Tóm lại, vì đa thừa kế.
Trong dài:
#include <iostream>
struct A { int a; };
struct B { int b; };
struct C : A, B { int c; };
int main() {
C c;
std::cout << "C is at : " << (void*)(&c) << "\n";
std::cout << "B is at : " << (void*)static_cast<B*>(&c) << "\n";
std::cout << "A is at : " << (void*)static_cast<A*>(&c) << "\n";
}
Output:
C is at : 0x22ccd0
B is at : 0x22ccd4
A is at : 0x22ccd0
Lưu ý rằng để chuyển đổi một cách chính xác đến B *, static_cast có thay đổi giá trị con trỏ. Nếu trình biên dịch không có định nghĩa lớp cho C, thì nó sẽ không biết rằng B là một lớp cơ sở, và chắc chắn nó sẽ không biết những gì bù đắp để áp dụng.
Nhưng trong tình huống đó mà không có định nghĩa là có thể nhìn thấy, static_cast không cư xử như reinterpret_cast, nó bị cấm:
struct D;
struct E;
int main() {
E *p1 = 0;
D *p2 = static_cast<D*>(p1); // doesn't compile
D *p3 = reinterpret_cast<D*>(p1); // compiles, but isn't very useful
}
Một dàn diễn viên đồng bằng C-phong cách, (B*)(&c)
làm những gì bạn nói: nếu định nghĩa của struct C có thể nhìn thấy, cho thấy rằng B là một lớp cơ sở, sau đó nó giống như một static_cast. Nếu các kiểu chỉ được khai báo về phía trước, thì nó sẽ giống như một kiểu reinterpret_cast. Điều này là do nó được thiết kế tương thích với C, có nghĩa là nó phải làm những gì C thực hiện trong trường hợp có thể trong C.
static_cast luôn biết phải làm gì với các kiểu tích hợp sẵn, đó thực sự là những gì được tích hợp sẵn có nghĩa. Nó có thể chuyển đổi int sang phao, v.v. Vì vậy, đó là lý do tại sao nó luôn an toàn cho các loại số, nhưng nó không thể chuyển đổi con trỏ trừ khi (a) nó biết những gì họ trỏ đến, và (b) có loại mối quan hệ đúng giữa các loại được chỉ định. Do đó, nó có thể chuyển đổi int
thành float
, nhưng không phải int*
thành float*
.
Như AndreyT nói, có một cách mà bạn có thể sử dụng static_cast
không an toàn, và trình biên dịch có thể sẽ không giúp bạn tiết kiệm, vì mã là hợp pháp:
A a;
C *cp = static_cast<C*>(&a); // compiles, undefined behaviour
Một trong những điều có thể làm là static_cast
"downcast" một con trỏ đến một lớp dẫn xuất (trong trường hợp này, C là một lớp dẫn xuất của A). Nhưng nếu referand không thực sự thuộc lớp dẫn xuất, bạn sẽ phải chịu số phận. A dynamic_cast
sẽ thực hiện kiểm tra trong thời gian chạy, nhưng đối với lớp C ví dụ của tôi, bạn không thể sử dụng dynamic_cast
, vì A không có chức năng ảo.
Bạn cũng có thể làm những việc không an toàn tương tự với static_cast
đến và đi từ void*
.
Nhiều kế thừa không phải là vấn đề duy nhất, câu trả lời của AndreyT giải quyết vấn đề downcasting đến sai loại. –
Đúng, tôi chỉ trả lời đầy đủ đoạn đầu của câu hỏi, và một phần đoạn thứ hai. Không phải là vấn đề lớn (trong tiêu đề) của an toàn tĩnh. –