2011-11-26 34 views
7

Điều này làm tôi ngạc nhiên một chút, nhưng tôi đã chơi xung quanh với một số mã và phát hiện ra rằng, ít nhất là trên máy tính của tôi, khi một hàm chấp nhận một lớp cha bằng cách tham chiếu và bạn vượt qua một thể hiện con. t xảy ra. Để minh họa:Việc truyền qua tham chiếu có luôn tránh vấn đề cắt không?

#include <iostream> 

class Parent 
{ 
public: 
    virtual void doSomething() 
    { 
     using namespace std; 
     cout << "Parent::DoSomething" << endl; 
    } 
}; 

class Child : public Parent 
{ 
public: 
    virtual void doSomething() 
    { 
     using namespace std; 
     cout << "Child::DoSomething" << endl; 
    } 
}; 

void performSomething(Parent& parent) 
{ 
    parent.doSomething(); 
} 

int main(int argc, char** argv) 
{ 
    Child myChild; 

    performSomething(myChild); 

    return 0; 
} 

Điều này in ra Child::DoSomething.

Như tôi đã nói, tôi hơi ngạc nhiên. Ý tôi là, tôi biết rằng việc chuyển qua tham chiếu là như các con trỏ đi qua (nhưng an toàn hơn nhiều trong sự hiểu biết của tôi), nhưng tôi không biết tôi vẫn giữ được sự tốt đẹp đa hình khi làm như vậy.

Tôi chỉ muốn đảm bảo, điều này có nghĩa vụ phải xảy ra hay là một trong những kiểu "nó hoạt động trên máy của tôi"?

+0

Đó không phải là những gì "cắt". Ngoài ra, mã đó thậm chí còn biên dịch? 'Sử dụng std; 'là gì? –

+0

Có nghĩa là nó là 'sử dụng không gian tên std'. Tôi nghĩ rằng tôi đã có thể nhận được điểm trên, nhưng làm sạch mã cho lợi ích tổng thể cho trang web. – Anthony

Trả lời

9

Hành vi bạn thấy là chính xác. Đây là cách nó được cho là hoạt động. Tài liệu tham khảo hoạt động giống như con trỏ.

+0

Cảm ơn, đó là những gì tôi đã tìm. Như tôi đã đề cập, tôi chỉ muốn kiểm tra sự tỉnh táo nên tôi không đưa ra giả định không hợp lệ. – Anthony

2

Có, ràng buộc với tham chiếu cho phép ràng buộc động. Điều này là do sự khác biệt của loại động của một đối tượng và kiểu tĩnh của nó.

Nếu bạn lấy tham số của mình theo giá trị, nó sẽ trở thành lớp Parent. Mặc dù nếu bạn vượt qua một cái gì đó thông qua một tài liệu tham khảo hoặc một con trỏ và gọi một chức năng ảo, thời gian chạy sẽ tìm kiếm các dynamic type hoặc most-derived type của đối tượng thực tế đang được tham chiếu.

3

Đó là nghĩa vụ phải xảy ra. Đi qua tham chiếu là CHÍNH XÁC như là con trỏ đi qua - nó làm điều tương tự dưới mui xe. Không có ma thuật cho điều này; mọi thể hiện của một đối tượng đa hình có một bảng chức năng ảo được liên kết với nó. Miễn là bạn không sao chép bất cứ điều gì, bạn sẽ không mất thông tin đó và các cuộc gọi chức năng ảo của bạn sẽ hoạt động theo cách bạn mong đợi.

Lý do bạn gặp sự cố khi truyền theo giá trị là nó sẽ sử dụng hàm tạo bản sao của loại bạn đã chỉ định trong chữ ký hàm, vì vậy bạn kết thúc với một thể hiện hoàn toàn mới của siêu lớp.

11

"Cắt" đề cập đến tính không có khả năng của trình tạo bản sao cơ sở để phân biệt các kết quả khớp chính xác từ các lớp dẫn xuất. Cách duy nhất để gọi slicing là gọi hàm tạo bản sao cơ bản. Thông thường điều này xảy ra khi đi qua lập luận theo giá trị, mặc dù các tình huống khác có thể được contrived:

class Base { }; 
class Derived : public Base { }; 

void foo(Base); 

int main() 
{ 
    Derived x; 

    Base y = x; // flagrant slicing 
    foo(x);  // slicing by passing by value 
} 

Bạn sẽ không bao giờ làm bất cứ điều gì như vậy, do đó bạn không gặp bất kỳ tình huống cắt.

+2

Đề cập đến các nhà xây dựng bản sao khi đi qua giá trị là những gì làm cho câu trả lời này hoàn hảo. – dani

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