2011-08-23 33 views
5

Tôi đã viết một trình bao bọc C++ nhỏ xung quanh một số phần của GSL và gặp phải câu đố sau đây (đối với tôi). Mã (giảm xuống còn yếu tố cần thiết của nó) như sau:Gọi không rõ ràng của các nhà xây dựng quá tải do lớp siêu (vượt qua giá trị)

#include <stdlib.h> 
    struct gsl_vector_view {}; 

    class Vector : protected gsl_vector_view { 
      public: 
      Vector (const Vector& original); 
      Vector (const gsl_vector_view view); 
    }; 

    class AutoVector : public Vector { 
      public: 
      explicit AutoVector (const size_t dims); 
    }; 

    void useVector (const Vector b) {} 

    void test() { 
      const AutoVector ov(2); 
      useVector(ov); 
    } 

sẽ không biên dịch sử dụng gcc 4.4.5 g ++ -c v.cpp nhưng mang lại

 In function ‘void test()’: 
    19: error: call of overloaded ‘Vector(const AutoVector&)’ is ambiguous 
    7: note: candidates are: Vector::Vector(gsl_vector_view) 
    6: note:     Vector::Vector(const Vector&) 
    19: error: initializing argument 1 of ‘void useVector(Vector)’ 

Tôi ngạc nhiên rằng bảo vệ lớp cơ sở gsl_vector_view được đưa vào xem xét bởi các cuộc gọi của useVector (Vector). Tôi đã nghĩ rằng useVector thuộc về "công chúng" trong cách nói của "Ngôn ngữ lập trình C++", thứ ba e., P. 405 và do đó không có quyền truy cập vào thông tin được bảo vệ đó, và do đó, không thể bị nhầm lẫn bởi nó. Tôi biết rằng tôi có thể thoát khỏi sự nhập nhằng bằng cách tuyên bố các nhà xây dựng như

explicit Vector (const gsl_vector_view view); 

Những gì tôi không biết (và, một cách trung thực, không hiểu hoặc), đó là sự không rõ ràng của cuộc gọi quá tải sẽ biến mất khi tôi khai báo hàm tạo là

Vector (const gsl_vector_view& view); 

tức là chuyển đối số theo tham chiếu (tôi vẫn xem xét cách làm đúng).

+0

+1, Nó không liên quan gì đến việc thừa kế 'được bảo vệ'; để định dạng lại câu hỏi. – iammilind

+0

btw. sự mơ hồ biến mất khi bạn khai báo useVector để tham chiếu – PlasmaHH

Trả lời

4

Phân giải quá tải được thực hiện trước khi kiểm tra quyền truy cập, đó là lý do tại sao ngay cả các thành viên của lớp cơ sở được bảo vệ cũng được xem xét.

Độ phân giải quá tải được mô tả trong chương 13.3 của tiêu chuẩn. Giải thích của tôi là ràng buộc const AutoVector ov đến Vector (const Vector& original);chuyển đổi do người dùng xác định, một chuyển đổi từ cơ sở bắt nguồn từ cơ sở ([13.3.3.1.4/1]) loại. Đối với Vector (const gsl_vector_view view);, trình tự chuyển đổi cũng là chuyển đổi do người dùng xác định do chuyển đổi là lvalue-to-rvalue theo sau bởi chuyển đổi do người dùng xác định. Vì vậy, cả hai chuỗi chuyển đổi được coi là bằng nhau, không có gì tốt hơn so với cái kia và do đó bạn có được sự mơ hồ.

Bây giờ, nếu bạn thay đổi ctor thành Vector (const gsl_vector_view& view);, cả hai chuyển đổi là chuyển đổi giá trị sang giá trị theo sau chuyển đổi do người dùng xác định (Chuyển đổi từ cơ sở sang chuyển đổi cơ sở). Hai thứ đó có thể được đặt hàng ([13.3.3.2/4]) và việc chuyển đổi sang const Vector& được coi là tốt hơn và do đó không có sự mơ hồ.

1

Câu hỏi không liên quan đến số protected thừa kế hoặc hàm tạo như vậy. Vấn đề này sẽ vẫn tồn tại với chức năng gọi bình thường cũng (với bất kỳ thừa kế nào).

Khi bạn đi ngang qua tham chiếu trong tất cả các phiên bản quá tải, thì lớp cơ sở gần nhất được chọn (nếu có nhiều hơn 1 lớp cơ sở gần nhất thì nó bị hình thành).

Trong trường hợp vượt qua theo giá trị, tất cả các chức năng đều được coi là ứng cử viên tốt. Vì vậy, bạn đang nhận được lỗi biên dịch này. Có một đoạn trích nhỏ từ tiêu chuẩn, phù hợp với phần nào câu hỏi của bạn.

§ 13.3.1 (5)
...Đối với các hàm thành viên không tĩnh được khai báo không có bộ kiểm định loại , quy tắc bổ sung sẽ áp dụng: - ngay cả khi tham số đối tượng ẩn không đủ điều kiện, giá trị có thể bị ràng buộc với tham số miễn là tất cả các khía cạnh khác đối số có thể được chuyển đổi thành loại tham số đối tượng ẩn.

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