2015-06-05 22 views

Trả lời

7

[class.virtual]/p7, tôi nhấn mạnh:

Kiểu trả về của một chức năng quan trọng hơn sẽ là một trong hai giống hệt nhau để kiểu trả về của hàm bị ghi đè hoặc covariant với các lớp chức năng . Nếu một hàm D::f ghi đè một chức năng B::f, các loại trở lại của các chức năng là hiệp biến nếu họ đáp ứng các tiêu chí sau:

  • cả hai đều là con trỏ để lớp, cả hai đều là tài liệu tham khảo giá trị trái để lớp, hoặc cả hai đều là tài liệu tham khảo rvalue để lớp [chú thích bỏ qua]
  • [...]

Từ trang 294-5 của D&E:

Afer một số xem xét các lựa chọn thay thế, chúng tôi quyết định cho phép trọng của một B* bởi một D* và một B& bởi một D& nơi B là một cơ sở có thể truy cập của D. Ngoài ra, bạn có thể thêm const hoặc trừ bất kỳ nơi nào an toàn. Chúng tôi đã quyết định không để thư giãn các quy tắc để cho phép chuyển đổi có tính khả thi về mặt kỹ thuật như một D một truy cập cơ sở B, một D một XD có một chuyển đổi, int* để void*, double để int, vv Chúng tôi cảm thấy rằng lợi ích từ cho phép chuyển đổi như vậy thông qua ghi đè sẽ không vượt quá chi phí triển khai và khả năng gây nhầm lẫn cho người dùng.

+2

Sẽ rất tuyệt nếu bạn có thể giải thích "lý do" đằng sau thiết kế này. – Mehrdad

+1

@Mehrdad Đã thêm báo giá D & E. –

+0

Khi tôi xem xét vấn đề với hiệp phương sai và các giới hạn của các không gian tên trong C++ thì tôi có thể phân biệt được lý do đằng sau đối tượng và gói của Java. – ady

0

Tính năng loại trả về biến thể là khi, một lớp dẫn xuất cung cấp loại trả về cụ thể/hẹp hơn cho hàm bị ghi đè. Kiểu trả về lớp dẫn xuất được gọi là biến thể.

int * không kiểu void * trong khi một cái gì đó như thế này không mô tả hiệp biến kiểu trả về:

struct Base { 
    virtual void *foo(); 
    virtual Base* func(); 
}; 
struct Derived : Base { 
// int *foo(); 
    Derived* func(); //COVARIANT RETURN TYPE 
}; 
+0

Bạn đang giải thích định nghĩa "hiệp phương sai", OP hỏi "Tại sao". – iammilind

1

Hiệp phương sai giữa void*T* không được phép bởi vì:

1. thiếu nhất quán.

Cách hiện tại của hiệp phương sai là tầm thường để hiểu và không gây nhầm lẫn.
Chỉ cần tưởng tượng về void* loại hiệp phương sai được cho phép. Đối với 1 giai đoạn của derivation là tốt, nhưng sau đó nó sẽ tạo ra sự nhầm lẫn. ví dụ .:

struct void_ { virtual void* foo(); }; 
struct int_ : void_ { virtual int* foo(); }; 
struct double_ : int_ { virtual double* foo(); }; // int* to double* or void* to double* 

Trong hệ thống phân cấp thứ 3 của struct double_, người dùng sẽ bị nhầm lẫn rằng mặc dù double* để int* là không thể, tại sao đoạn code vẫn biên dịch? Chỉ sau khi kiểm tra các lớp hàng đầu nhất void_, nó được biết rằng đó là vì double* đến void* là "covariant". Cũng vậy với trình biên dịch cũng :-)

2. Vấn đề với các tài liệu tham khảo

Trong trường hợp của các lớp học, trở về B&/D*/DD* là có thể. Nhưng điều tương tự là không thể với void& và do đó int&, vv

3. Trộn của hiệp phương sai

Nếu void* được phép rồi sau cũng được phép vô ý.

struct void_ { virtual void* foo(); }; 
struct Base : void_ { virtual Base* foo(); }; 
struct Derived : Base { virtual int* foo(); }; // Look at `int*` 

Điều gì làm tăng thêm sự nhầm lẫn.

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