2012-08-15 39 views
8

Tôi đang trải qua một bài kiểm tra C++. Và đi qua đoạn mã sau - nó là bất hợp pháp, nhưng tôi không thể hiểu tại sao. Bất cứ ai có thể giải thích lý do tại sao dòng này:Thừa kế - tại sao điều này bất hợp pháp?

Box* b1 = s1->duplicate(); 

tạo lỗi trình biên dịch "không thể chuyển đổi từ hình dạng * thành hộp"? Tôi giả định rằng s1->duplicate() đang gọi Box::duplicate()s1 thực sự trỏ đến một Box - nhưng từ lỗi trình biên dịch có vẻ như nó đang gọi Shape::duplicate().

#include <iostream> 

struct Shape 
{ 
    virtual Shape* duplicate() 
    { 
    return new Shape; 
    } 

    virtual ~Shape() {} 
}; 

struct Box : public Shape 
{ 
    virtual Box* duplicate() 
    { 
    return new Box; 
    } 

}; 

int main(int argc, char** argv) 
{ 
    Shape* s1 = new Box; 

    Box* b1 = s1->duplicate(); 

    delete s1; 
    delete b1; 
    return 0; 
} 
+1

Do [t của anh ấy] (http://stackoverflow.com/questions/4665117/c-virtual-function-return-type). –

Trả lời

8

Shape::duplicates() trả lại Shape*, không phải là Box*. Loại thời gian chạy mà bạn thực sự quay lại không liên quan gì đến nó. Làm cách nào để trình biên dịch biết rằng Shape* trả về thực sự trỏ đến một số Box?

Chỉnh sửa: Hãy suy nghĩ về điều này:

struct Shape 
{ 
    virtual Shape* duplicate() 
    { 
    return new Shape; 
    } 

    virtual ~Shape() {} 
}; 

struct Box : public Shape 
{ 
    virtual Box* duplicate() 
    { 
    return new Box; 
    } 

}; 

struct Sphere : public Shape 
{ 
    virtual Sphere* duplicate() 
    { 
    return new Sphere; 
    } 

}; 

Shape* giveMeABoxOrASpehere() 
{ 
    if (rand() % 2) 
     return new Box; 
    else 
     return new Sphere; 
} 

// 
Shape* shape = giveMeABoxOrASphere(); 
// What does shape->duplicate() return? 

Box* shape = giveMeABoxOrASphere(); 
// shoud this compile? 
+0

Hmm. Vâng - Tôi cho rằng tôi đã suy nghĩ dọc theo các dòng, rằng nếu trình biên dịch có thể chấp nhận 'Shape * s' = new Box' thì nó sẽ bằng cách nào đó * biết * rằng' s1' bây giờ là một con trỏ tới một Box. Muộn rồi, tôi nghĩ não mình bị rán. . . – BeeBand

+2

@BeeBand: Có một sự khác biệt quan trọng giữa 'Shape * s = new Box;' và 'Box * b = new Shape;'. – aschepler

+1

@BeeBand trong trường hợp này, bạn có thể tìm ra bằng 'dynamic_cast', vì vậy thông tin kiểu không bị mất hoàn toàn. Nó chỉ không có sẵn cho trình biên dịch. –

15

Ngôn ngữ C++ được nhập tĩnh. Các quyết định về tính hợp pháp của cuộc gọi của bạn được thực hiện tại thời điểm biên dịch. Trình biên dịch, rõ ràng, không thể biết rằng s1->duplicate() trả về một con trỏ đến một đối tượng Box. Trong những trường hợp này, sẽ không hợp lý để mong đợi nó chấp nhận mã của bạn.

Có, s1->duplicate() thực sự gọi Box::duplicate trong ví dụ của bạn, nhưng làm thế nào để bạn mong đợi trình biên dịch biết điều này? Người ta có thể nói rằng nó là "rõ ràng" từ ví dụ cụ thể của bạn, nhưng đặc điểm kỹ thuật của tính năng ngôn ngữ này không có ngoại lệ cho các trường hợp "rõ ràng" như vậy.

1

Cũng vì lý do chính xác cùng

Shape* s1 = new Box; 
Box* b1 = s1; 

không biên dịch. Trình biên dịch không quan tâm đến số s1 đề cập đến một số Box và cũng không nên quan tâm.

Nếu bạn biết rằng s1 đề cập đến một Box, chỉ cần nói nó:

Box *s1 = new Box; 

Lưu ý về cú pháp: các quy tắc phân tích cú pháp cho Box * s1; là (rất đơn giản):

declaration := type-name declarator ; 
declarator := name 
      | * declarator 

nên phân tích cú pháp là:

Box  *  s1  ; 
        ^^^^^^^^ 
        declarator 
^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ 
type-name   declarator 

và nhóm là Box (* (s1))

Nó được coi là phong cách tốt nhất để viết Box *s1; vì nó là phù hợp hơn với các phân tích hơn Box* s1; Nếu bạn khai báo nhiều hơn một biến trong một tuyên bố, cú pháp Box* thể gây nhầm lẫn:

Box* x, y; 

x là một con trỏ đến Box, nhưng y là một Box, như phân tích cú pháp là:

Box (*x), y; 
+0

ok cảm ơn cho tip lại. phân tích cú pháp. . . – BeeBand

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