Tối ưu hóa cơ sở trống là tuyệt vời. Tuy nhiên, nó đi kèm với các hạn chế sau:
Tối ưu hóa cơ sở trống bị cấm nếu một trong các lớp cơ sở trống cũng là loại hoặc cơ sở của loại thành viên dữ liệu không tĩnh đầu tiên, do hai tiểu dự án cơ sở cùng loại được yêu cầu có các địa chỉ khác nhau trong biểu diễn đối tượng thuộc loại có nguồn gốc nhất.
Để giải thích hạn chế này, hãy xem xét các mã sau đây. Ý static_assert
chí thất bại. Trong khi đó, việc thay đổi Foo
hoặc Bar
thay thế kế thừa từ Base2
sẽ tránh được lỗi:
#include <cstddef>
struct Base {};
struct Base2 {};
struct Foo : Base {};
struct Bar : Base {
Foo foo;
};
static_assert(offsetof(Bar,foo)==0,"Error!");
Tôi hiểu hành vi này hoàn toàn. Điều tôi không hiểu là tại sao hành vi cụ thể này tồn tại . Nó rõ ràng đã được thêm vào vì một lý do, vì nó là một bổ sung rõ ràng, không phải là một giám sát. Một lý do cho việc này là gì?
Cụ thể, tại sao hai tiểu dự án cơ sở phải được yêu cầu có địa chỉ khác nhau? Ở trên, Bar
là một loại và foo
là một biến thành viên của loại đó. Tôi không thấy lý do tại sao lớp cơ sở của Bar
vấn đề đối với lớp cơ sở thuộc loại foo
hoặc ngược lại.
Thật vậy, tôi nếu có bất cứ điều gì, tôi sẽ mong đợi đó &foo
giống như địa chỉ của Bar
cá thể có chứa nó vì nó được yêu cầu trong các tình huống khác (1) . Rốt cuộc, tôi không làm bất cứ điều gì lạ mắt với virtual
sự kế thừa, các lớp cơ sở trống bất kể và việc biên dịch với các Base2
chương trình cho thấy không có gì phá vỡ trong trường hợp cụ thể này.
Nhưng rõ ràng lý do này là không chính xác bằng cách nào đó, và có những tình huống khác mà giới hạn này sẽ được yêu cầu.
Giả sử câu trả lời nên dành cho C ++ 11 hoặc mới hơn (Tôi hiện đang sử dụng C ++ 17).
(1) Lưu ý: EBO đã được nâng cấp trong C ++ 11 và đặc biệt trở thành bắt buộc đối với StandardLayoutType
s (mặc dù Bar
, ở trên, không phải là a StandardLayoutType
).
Base *a = new Bar(); Base *b = a->foo;
vớia==b
, nhưnga
vàb
rõ ràng đối tượng khác nhau (có lẽ có ghi đè phương pháp ảo khác nhau).