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_assertchí thất bại. Trong khi đó, việc thay đổi Foohoặc Barthay thế kế thừa từ Base2sẽ 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, Barlà một loại và foolà 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 Barvấn đề đối với lớp cơ sở thuộc loại foohoặ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 đó &foogiống như địa chỉ của Barcá 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 virtualsự 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 Base2chươ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 StandardLayoutTypes (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ưngavàbrõ ràng đối tượng khác nhau (có lẽ có ghi đè phương pháp ảo khác nhau).