2012-06-16 40 views
11

Điều gì xảy ra trong ví dụ sau?Tham chiếu lớp cơ sở - gán loại khác cho nó

struct B { }; 
struct D1 : B { }; 
struct D2 : B { }; 
int main() 
{ 
    D1 d; 
    D2 d2; 
    B& x = d; 
    x = d2; 
} 

Tôi biết tham chiếu không được chỉ định lại. x vẫn đề cập đến d, nhưng sau đó làm cách nào bạn có thể chỉ định d2 đến d?

Một số chi tiết:

struct B 
{ 
    B() { x = 0; } 
    int x; 
    virtual void foo() { cout << "B" << endl; } 
}; 
struct D1 : B 
{ 
    D1() { x = 1; } 
    virtual void foo() { cout << "D1" << endl; } 
}; 
struct D2 : B 
{ 
    D2() { x = 2; } 
    virtual void foo() { cout << "D2" << endl; } 
}; 

int main() 
{ 
D1 d; 
D2 d2; 
B& x = d; 
x.foo(); //D1 
       //x.x is 1 here 
x = d2; 
x.foo(); //also D1 
       //but x.x is 2 here 
} 

Nó có vẻ như x.x đã được cập nhật, nhưng vftable không ... Tại sao?

+0

+1. Câu hỏi hay. – Nawaz

Trả lời

11

x đề cập đến lớp cơ sở Bsubobject của d. Việc chỉ định x = d2slices đơn vị cơ sở B từ d2 và gán giá trị của nó cho giá trị con của d.

Điều này thường không được thực hiện cố ý.

EDIT:

Nó có vẻ như x.x đã được cập nhật, nhưng vftable không ... Tại sao?

Đó là những gì toán tử gán B::operator= thực hiện. Các lớp cơ sở trong C++ hoàn toàn không biết rằng chúng là các lớp cơ sở. Ngoài ra, loại của một đối tượng không bao giờ có thể được thay đổi trong suốt cuộc đời của nó. Cách thay thế gần nhất là std::move của C++ 11, có thể chuyển đối tượng B cũ bên trong một D1 thành đối tượng D2 mới. Sau đó bạn sẽ phá hủy vật thể cũ.

+0

Hmm, có thể sao chép bài tập được tạo thành 'virtual', bằng cách này? (quá lười biếng để thử/tìm kiếm nó) –

+0

Tôi nghĩ rằng việc sử dụng tài liệu tham khảo sẽ ngăn chặn việc cắt ... không? – AMCoder

+0

Thành thật mà nói, tôi không biết điều này. Thực ra tôi đã không nghĩ về điều này trước đây. +1. – Nawaz

1

Trong trường hợp của bạn, khi bạn chỉ định theo cách này, các thành viên, không thuộc về lớp Cơ sở sẽ bị cắt. Có nghĩa là, trong trường hợp này nó được sao chép như thể bạn đã gán một đối tượng lớp cơ sở cho một đối tượng lớp cơ sở khác.

+0

Bạn đang nói về đối tượng cắt (nguyên nhân đó là những gì nó được gọi là)? – AMCoder

+0

Vâng, tôi đã quên thuật ngữ này. – Spo1ler

3

Nếu muốn, bạn có thể tự mình thực hiện lệnh = và tránh "cắt" bằng cách kiểm tra loại bê tông thích hợp (hoặc đưa ra lỗi). Xem ví dụ dưới đây có lỗi.

struct B { 
    virtual B& operator = (B& b) = 0; 
}; 
struct D1 : B { 
    D1& operator = (B& b) { 
    if (dynamic_cast<D1*>(&b) == 0) { 
     cerr << "Cannot assign non D1 to D1" << endl; 
     exit(255); 
    } 
    // handle the assignments 
    return *this; 
    } 
}; 
struct D2 : B { 
    int c; 
    D2& operator = (B& b) { 
    if (dynamic_cast<D2*>(&b) == 0) { 
     cerr << "Cannot assign non D2 to D2" << endl; 
     exit(255); 
    } 
    // handle the assignments 
    return *this; 
    } 
}; 
+0

Tôi nghĩ rằng anh ấy hỏi về hành vi, không phải cách đi xung quanh nó ... –

+0

Đây không phải là điều tôi đang yêu cầu ... – AMCoder

+0

+1, ý tưởng hay, nhưng 'ném' sẽ tốt hơn' thoát'. – Potatoswatter

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