2011-01-16 49 views
8

xem xét mã này,chuyển đổi ngầm định: tham chiếu const vs tham chiếu không const vs phi tham khảo

struct A {}; 
struct B { B(const A&) {} }; 
void f(B) 
{ 
    cout << "f()"<<endl; 
} 
void g(A &a) 
{ 
    cout << "g()" <<endl; 
    f(a); //a is implicitly converted into B. 
} 
int main() 
{ 
    A a; 
    g(a); 
} 

compiles fine này, chạy tốt. Nhưng nếu tôi thay đổi f(B) thành f(B&), nó doesn't compile. Nếu tôi viết f(const B&), nó lại compiles fine, chạy tốt. Tại sao lý do và lý do?

Tóm tắt:

void f(B);   //okay 
void f(B&);  //error 
void f(const B&); //okay 

Tôi muốn nghe lý do này, lý do và tài liệu tham khảo (s) từ đặc tả ngôn ngữ, cho mỗi trường hợp này. Tất nhiên, bản thân chữ ký chức năng không chính xác. Thay vào đó, A chuyển đổi hoàn toàn thành Bconst B&, nhưng không chuyển thành B& và gây ra lỗi biên dịch.

Trả lời

7

Tôi muốn nghe lý do này, lý do và tài liệu tham khảo (s) từ đặc tả ngôn ngữ

Design và Sự phát triển của C++ đủ?

Tôi đã mắc phải một sai lầm nghiêm trọng, bằng cách cho phép tham chiếu không phải const được khởi tạo bởi một lời nhận xét không phải lvalue [của tôi: từ ngữ đó là không chính xác!]. Ví dụ:

void incr(int& rr) { ++rr; } 

void g() 
{ 
    double ss = 1; 
    incr(ss); // note: double passed, int expected 
       // (fixed: error in release 2.0) 
} 

Do sự khác biệt trong loại các int& không thể tham khảo các double qua do đó, một tạm thời được tạo ra để tổ chức một int khởi tạo bởi giá trị ss 's. Do đó, incr() đã sửa đổi tạm thời và kết quả không được phản ánh trở lại chức năng gọi điện [nhấn mạnh mỏ].

Hãy suy nghĩ về nó: Toàn bộ vấn đề của cuộc gọi-by-reference là các khách hàng qua mọi thứ được thay đổi bởi các chức năng, và sau khi trở về chức năng, khách hàng phải có khả năng quan sát những thay đổi.

+0

Một điều thú vị: Trong ARM, việc xác định độ chính xác cho biểu thức chính như sau: "Kết quả là một giá trị nếu từ định danh là". .. "Kết quả là một lvalue nếu thành viên là.". Tôi đã tự hỏi những gì heck có nghĩa là, bởi vì nó cũng định nghĩa "Một lvalue là một biểu hiện đề cập đến một đối tượng hoặc chức năng.". Hmm, có lẽ nó chỉ có nghĩa là "Kết quả là một lvalue nếu nó đề cập đến một đối tượng hoặc chức năng."? –

+0

Điều này là tốt. Tôi nghĩ rằng nó tốt hơn câu trả lời cho câu hỏi của tôi, vì nó giải thích lý do tại sao nó không được phép. Tôi chấp nhận điều này như là câu trả lời cho câu hỏi của tôi. :-) – Nawaz

4

Vấn đề là chuyển đổi ngầm từ một đối tượng B thành giá trị rvalue. Tham chiếu không phải const chỉ có thể liên kết với các giá trị.

Nếu B có hàm tạo mặc định, bạn sẽ nhận được cùng một hành vi nếu bạn thay đổi cuộc gọi f(a) thành f(B()).

-

litb cung cấp một câu trả lời tuyệt vời để một giá trị trái là gì: Stack Overflow - often used seldom defined terms: lvalue

GotW #88: A Candidate For the “Most Important const”

Stack Overflow - How come a non-const reference cannot bind to a temporary object?

-

Để giải thích với tham chiếu đến các tiêu chuẩn như thế nào các cuộc gọi hàm đó thất bại hoặc thành công sẽ quá dài. Điều quan trọng là làm thế nào B& b = a; không thành công trong khi const B& b = a; không thất bại.

(từ dự thảo n1905)

Một tham chiếu đến gõ “CV1 T1” được khởi tạo bởi một biểu hiện của loại “CV2 T2” như sau:
- [ là một giá trị trái và là một trong hai tài liệu tham khảo tương thích hoặc ngầm chuyển đổi thành một giá trị của một loại tương thích tham chiếu ... ]
- Nếu không, tham chiếu phải là loại const không bay hơi (ví dụ, cv1 phải là const).

Here's trường hợp có thể chuyển đổi thành giá trị tương đương với loại tương thích tham chiếu.

+0

Tại sao câu hỏi của @ Nawaz không được trả lời trong 23 phút, và khi tôi anwered nó, bạn đã cung cấp câu trả lời 30 giây trước tôi. Đó là phép thuật! Haha, +1. –

+0

@ Chris: Vui lòng trích dẫn các tài liệu tham khảo có liên quan, để tôi có thể tự mình khám phá các khái niệm liên quan. – Nawaz

+3

Nói đúng, bạn không thể tạo ra các giá trị hoặc giá trị ở tất cả, vì giá trị-thể loại là một thuộc tính của * biểu thức * (thời gian biên dịch), không phải * đối tượng * (thời gian chạy). – fredoverflow

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