2013-02-08 14 views
11

Trong khoản 27 của "Effective C++" (3rd Edition, trang 118), Scott Meyers nói:Nhiều hơn 1 địa chỉ cho đối tượng lớp dẫn xuất?

class Base { ... }; 
class Derived: public Base { ... }; 
Derived d; 
Base *pb = &d; 

Ở đây chúng tôi chỉ tạo ra một con trỏ lớp cơ sở cho một đối tượng lớp được thừa kế, nhưng đôi khi, hai con trỏ sẽ không giống nhau. Khi đó là trường hợp, một bù đắp được áp dụng khi chạy đến con trỏ Derived* để có được giá trị con trỏ Base* chính xác.

ví dụ cuối cùng này cho thấy rằng một đối tượng duy nhất (ví dụ, một đối tượng kiểu Derived) có thể có nhiều hơn một địa chỉ (ví dụ, địa chỉ của nó khi được trỏ đến bởi một con trỏ Base* và địa chỉ của nó khi được trỏ đến bởi một con trỏ Derived*) .

Dưới đây là một chút khó hiểu. Tôi biết rằng một con trỏ đến lớp cơ sở có thể trỏ đến một đối tượng của lớp dẫn xuất trong thời gian chạy, điều này được gọi là đa hình hoặc ràng buộc động. Nhưng đối tượng lớp dẫn xuất có thực sự có nhiều hơn 1 địa chỉ trong bộ nhớ không?

Đoán tôi có một số hiểu lầm ở đây. Ai đó có thể cho một số làm rõ? Có lẽ điều này có liên quan đến sự đa hình được thực hiện trong trình biên dịch C++ như thế nào?

Trả lời

13

Chỉ cần cố gắng nó:

class B1 
{ 
    int i; 
}; 

class B2 
{ 
    int i; 
}; 

class D : public B1, public B2 
{ 
    int i; 
}; 

int 
main() 
{ 
    D aD; 
    std::cout << &aD << std::endl; 
    std::cout << static_cast<B1*>(&aD) << std::endl; 
    std::cout << static_cast<B2*>(&aD) << std::endl; 
    return 0; 
} 

Không có cách nào có thể cho B1 sub-object để có cùng một địa chỉ như B2 sub-object.

4

Một đối tượng có chính xác một địa chỉ; đó là nơi nó nằm trong bộ nhớ. Khi bạn tạo một con trỏ tới một số base subobject bạn nhận được địa chỉ của subobject đó và không cần phải giống với địa chỉ của đối tượng chứa nó. Một ví dụ đơn giản:

struct S { 
    int i; 
    int j; 
}; 

S s; 

Địa chỉ s sẽ khác với địa chỉ s.j.

Tương tự, địa chỉ của một đối tượng con cơ sở không nhất thiết phải giống với địa chỉ của đối tượng dẫn xuất. Với kế thừa đơn thường là, nhưng khi nhiều thừa kế đi vào chơi, và bỏ qua các lớp cơ sở trống, thì hầu hết một trong các lớp con cơ sở có thể có cùng địa chỉ với đối tượng dẫn xuất. Vì vậy, khi bạn chuyển đổi một con trỏ sang đối tượng có nguồn gốc thành một con trỏ đến một trong các căn cứ của nó, bạn không nhất thiết phải nhận được cùng một giá trị như địa chỉ của đối tượng dẫn xuất.

+0

"với kế thừa đơn thường là" - bạn có thể nghĩ ra bất kỳ trường hợp nào mà nó * sẽ không *? – us2012

+4

@ us2012: Lớp cơ sở không đa hình, lớp dẫn xuất đa hình, con trỏ vtable được thêm tại offset 0 trong lớp dẫn xuất, tiếp theo là lớp cơ sở. – MSalters

+0

@MSalters Đẹp! Cảm ơn. – us2012

Các vấn đề liên quan