2011-06-29 30 views
6

Tiếp theo là các mã kiểm tra:Tại sao phiên bản không phải là const được chọn trong phiên bản const cho lớp học?

struct A 
{ 
    operator int(); 
    operator int() const; 
}; 

void foo (const int); 

Bây giờ, khi gọi:

foo(A()); // calls A::operator int() 

Tại sao nó always chooses the non-const version? Thậm chí làm cho operator const int() const; không có bất kỳ ảnh hưởng nào khi gọi foo(). Ngoài tham chiếu tiêu chuẩn, ai đó có thể giải thích một cách hợp lý, lý do đằng sau nó?

Trả lời

13

A() cung cấp cho bạn đối tượng A tạm thời không đủ điều kiện. Biểu thức A() là biểu thức rvalue, có, nhưng điều đó không làm cho đối tượng A const đủ điều kiện.

Vì đối tượng A không đủ điều kiện, không phải là const operator int() là kết hợp chính xác và const operator int() yêu cầu chuyển đổi tiêu chuẩn, do đó quá tải không phải là const được chọn là đối sánh tốt nhất.

Nếu bạn muốn nó được const-đủ điều kiện, bạn cần phải yêu cầu một cách rõ ràng const trình độ A:

foo(identity<const A>::type()); 

nơi identity được định nghĩa là

template <typename T> 
struct identity { typedef T type; }; 

Lưu ý rằng có thực sự không có sự khác biệt giữa operator const int() constoperator int() const: kết quả là một rvalue và chỉ loại giá trị rvalues ​​có thể const-đủ điều kiện (int không phải là một loại lớp).

Cũng lưu ý rằng không có sự khác biệt giữa void foo(const int) mà bạn có và void foo(int). Các loại vòng loại cấp cao nhất trên các loại tham số không ảnh hưởng đến loại hàm (nghĩa là loại của cả hai khai báo đó là void foo(int)). Trong số các lý do khác, điều này là bởi vì nó không quan trọng đối với người gọi cho dù có một cấp bậc const-vòng loại; nó phải tạo một bản sao bất kể. Trình điều khiển vòng loại cấp cao chỉ ảnh hưởng đến định nghĩa của hàm.

+0

Thậm chí 'A' là một chồng/đống phân bổ đối tượng bình thường (không phải tạm thời), nó mang lại cho kết quả tương tự. – iammilind

+0

Nếu đối tượng không đủ điều kiện, sự quá tải không const sẽ phù hợp hơn trong quá trình phân giải quá tải. Có lý do nào bạn mong đợi điều này không đúng không? –

+0

Tại sao tôi bị lẫn lộn là, ngay cả khi 'foo()' nhận 'const int' và chúng ta có toán tử' A :: const int() const; ', nó vẫn đi và chọn toán tử' A :: int' bình thường . – iammilind

4

Một quy tắc bạn phải nhớ về C++: nó không bao giờ tính đến giá trị đang được trả lại khi chọn quá tải. Trong trường hợp này vì hàm operator int không có tham số, nó không thể sử dụng danh sách tham số để thu hẹp lựa chọn. Tất cả nó có thể sử dụng nó các constness của đối tượng mà nó được gọi là từ. Vì đây là một đối tượng tạm thời mới, nó không phải là const, vì vậy nó không chọn quá tải const.

+1

* Không bao giờ * có lẽ quá mạnh; khi lấy địa chỉ của một hàm, và khi giải quyết toán tử chuyển đổi cho một chuyển đổi tự động (sau này có thể khá hữu ích khi bạn muốn có một hàm bị quá tải trên kiểu trả về.) –

5

James McNellis ’ câu trả lời thực sự đã đề cập đến tất cả, nhưng nó không ’ tổn thương (Tôi hy vọng) với nhiều giải thích hơn.

So.

Khi bạn gọi & hellip;

o.operator int() 

& hellip; sau đó việc lựa chọn quá tải phụ thuộc hoàn toàn vào độ chói của o.

Không có gì khác.

Để xem lý do tại sao, hãy xem xét lớp này:

struct Bar 
{ 
    void f() {} 
    void f() const {} 
}; 

Về mặt kỹ thuật những hàm thành viên không cần phải có hàm thành viên. Họ cũng có thể được chọn là chức năng đứng tự do. Nhưng sau đó họ cần Bar luận:

struct Bar 
{}; 

void f(Bar&) {} 
void f(Bar const&) {} 

Và hy vọng bây giờ nó dễ dàng hơn để thấy rằng khi bạn làm

Bar o; 
f(o); 

thì hàm đầu tiên thể được lựa chọn. Và do đó, nó là. Bởi vì nếu chức năng thứ hai được chọn, thì bạn sẽ không bao giờ có được chức năng thứ nhất. Bởi vì nếu bạn tạo đối tượng const, thì nó sẽ phá vỡ độ chính xác const để chọn đối tượng đầu tiên. Vì vậy, khi đối tượng là const chỉ có thể chọn thứ hai, do đó, khi nó không phải là const, cái đầu tiên được chọn.

Tóm lại, cách thay thế thực tế duy nhất cho quy tắc này sẽ là luôn luôn chọn giải pháp thứ hai, điều này sẽ khiến người đầu tiên thay thế vô dụng, phải không?

Cheers & h.,

+0

Nếu phiên bản không phải là const được đặt ở chế độ riêng tư, nó vẫn cố gắng sử dụng phiên bản đó thay vì phiên bản công khai, với lỗi "cố gắng truy cập thành viên riêng"; Rất khó chịu. – Oktalist

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