Nhiều kế thừa làm cho điều đó không đúng sự thật.
Điều đó không hoàn toàn chính xác. Xem xét ví dụ này:
struct A {};
struct B : A {};
struct C : A {};
struct D : B, C {};
Khi tạo một thể hiện của D
, B
và C
được khởi tạo mỗi dụ tương ứng của họ A
. Tuy nhiên, sẽ không có vấn đề gì nếu trường hợp D
có cùng địa chỉ của thể hiện của B
nó và thể hiện tương ứng của nó A
. Mặc dù không bắt buộc, đây chính xác là những gì xảy ra khi biên dịch với clang 11
và gcc 10
:
D: 0x7fffe08b4758 // address of instance of D
B: 0x7fffe08b4758 and A: 0x7fffe08b4758 // same address for B and A
C: 0x7fffe08b4760 and A: 0x7fffe08b4760 // other address for C and A
Liệu thừa kế ảo cũng làm cho điều đó không đúng sự thật
Hãy xem xét một phiên bản sửa đổi của ví dụ trên:
struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B, C {};
Sử dụng công virtual
cụ xác định chức năng thường được sử dụng để tránh các cuộc gọi chức năng mơ hồ. Do đó, khi sử dụng tính virtual
kế thừa, cả hai B
và các C
thể hiện phải tạo một A
thể hiện chung . Khi bắt đầu D
, chúng tôi nhận được các địa chỉ sau:
D: 0x7ffc164eefd0
B: 0x7ffc164eefd0 and A: 0x7ffc164eefd0 // again, address of A and B = address of D
C: 0x7ffc164eefd8 and A: 0x7ffc164eefd0 // A has the same address as before (common instance)
Mã sau đây có đúng không
Không có lý do ở đây để sử dụng reinterpret_cast
, thậm chí nhiều hơn, nó dẫn đến hành vi không xác định. Sử dụng static_cast
thay thế:
A* pA = static_cast<A*>(pB);
Cả hai diễn viên hành xử khác nhau trong ví dụ này. Các reinterpret_cast
sẽ diễn giải lại pB
như một con trỏ đến A
, nhưng con trỏ pA
có thể trỏ đến một địa chỉ khác nhau, như trong ví dụ trên (C vs A). Con trỏ sẽ được cập nhật chính xác nếu bạn sử dụng static_cast
.
reinterpret_cast
với các lớp luôn tanh (ngoại trừ từ lớp này sang lớp khácvoid*
và trở lại cùng lớp).