2015-02-07 16 views
5

Cố gắng tìm hiểu xem tại sao không quá tải-mơ hồ gây ra trong các mã sau:đèo bằng cách tham chiếu/giá trị quá tải

float foo2(float& i) 
{ 
    cout << "call from reference" << endl; 
    return i; 
} 
float foo2(float i) 
{ 
    cout << "call from non reference"<<endl; 
    return i; 
} 
int main() 
{ 
    cout<<foo2(2); // print "call from non reference" 
} 

Các foo2 có các tham số không được thông qua bằng cách tham khảo được gọi. Tại sao? Làm thế nào để gọi foo2 vượt qua tham số tham chiếu?

+1

_ "Làm cách nào để gọi foo2 vượt qua tham số tham chiếu?" _ Cung cấp cho nó tham chiếu? –

+0

[Trình biên dịch sẽ phàn nàn về sự mơ hồ] (http://ideone.com/W5eLdq) nếu bạn đang cố gắng sử dụng cuộc gọi không rõ ràng. –

+0

Cảm ơn tất cả, vấn đề được giải quyết – kchpchan

Trả lời

2

Số 2 bạn đã cung cấp làm tham số cho foo2 là một giá trị không phải là tham chiếu. Do đó, hàm chấp nhận một tham chiếu không thể được gọi với nó.

+0

'2' không phải là một tham chiếu rvalue, nó là một rvalue. Nó có thể * liên kết * với tham chiếu rvalue. (Mã trong câu hỏi không thể hiện sự mơ hồ, bạn sẽ phải thay đổi hàm đầu tiên thành 'const int &' t ocreate ambiguity.) –

+0

@remyabel Oh bạn nói đúng, sửa nó. – emlai

5

Các foo2 có các tham số không thông qua tham khảo được gọi. Tại sao?

Vì bạn không thể chuyển biểu thức hằng số hoặc bất kỳ biểu thức được tính bằng cách tham chiếu đến hàm lấy tham chiếu không liên tục. Để truyền một biểu thức bằng tham chiếu, bạn cần một giá trị được gán - một thứ có thể xuất hiện ở phía bên tay trái của một biểu thức gán. Vì 2 không thể xuất hiện ở phía bên trái của một biểu thức gán, nó không thể được sử dụng để gọi một hàm mong đợi một tham chiếu. Khi tham chiếu là const, bạn có thể truyền bất cứ điều gì, vì C++ sẽ tạo một biến tạm thời, gán biểu thức cho nó và chuyển tham chiếu đến hàm tham chiếu const.

Cách gọi số foo2 chuyển tham số tham chiếu?

Không có cách nào rõ ràng để làm điều đó, bởi vì lúc này bạn vượt qua một biến hoặc biểu hiện khác có thể trở thành một tài liệu tham khảo, trình biên dịch sẽ phàn nàn rằng bạn đang thực hiện cuộc gọi mơ hồ:

float f; 
foo2(f); // <<== This will not compile 

có một cách để gọi nó, mặc dù: bạn có thể làm cho một con trỏ hàm mà chỉ phù hợp với một trong hai chữ ký chức năng, và sử dụng nó để thực hiện cuộc gọi của bạn:

typedef float (*fptr_with_ref)(float&); 

int main() 
{ 
    cout<<foo2(2) << endl; // print "call from non reference" 
    fptr_with_ref foo2ptr(foo2); // Only one overload matches 
    float n = 10; 
    cout<<foo2ptr(n) << endl; // Calls foo2(float&) 
} 

Demo.

+0

Điều thú vị là 'int f; foo2 (f); 'sẽ biên dịch và dẫn đến một cuộc gọi đến hàm không tham chiếu (chỉ cần thử nó ra). Mặc dù tôi không thể nói tại sao. (** Chỉnh sửa ** hoàn nguyên chỉnh sửa vì @dasblinkenlight đã trả lời dưới đây, cảm ơn) – jadhachem

+1

@jadhachem Bởi vì trình biên dịch thực hiện cuộc gọi như thế này: 'foo2 ((float) f)'. Vì 'f' cần được chuyển đổi từ' int' sang 'float', không có sự mơ hồ. Nếu bạn tạo 'f' thành' float', bạn sẽ thấy sự mơ hồ. – dasblinkenlight

+0

@dasblinkenlight, cảm ơn câu trả lời của bạn. Khái niệm đã bị xóa. Câu trả lời của bạn không xuất hiện trước khi tôi làm mới trang. – kchpchan

1

Câu hỏi của bạn ở dạng C++, không theo thuật ngữ thiết kế. C++ hỗ trợ mọi thứ theo cách vì nó có ý nghĩa về mặt thiết kế. C++ cho phép bạn làm rất nhiều thứ, nhưng nếu bạn muốn tạo ra phần mềm tốt với nó, bạn không thể chỉ tuân thủ các quy tắc C++ theo nghĩa đen, bạn cần phải đi xa hơn. Trong thực tế điều đó có nghĩa là bạn kết thúc việc đưa ra các quy tắc của riêng bạn.

Trong trường hợp của bạn - tốt, tôi sẽ không bao giờ tạo biến thể tham chiếu nếu tôi không thực sự thay đổi biến trong hàm.

Nếu bạn áp dụng 'quy tắc' cho chính mình, thì bạn ngay lập tức thấy lý do tại sao chức năng ref không ràng buộc: điểm đầu tiên, để thay đổi hằng số lỏng lẻo là gì?

Nếu bạn thực hiện đúng quy tắc, bạn sẽ thấy chúng được C++ hỗ trợ đẹp mắt. Giống như ... function thay đổi một đối tượng: pass non-const ref. Không thay đổi? const ref. Không bắt buộc? con trỏ const. Tiếp quản quản lý mem? con trỏ không const.

Lưu ý rằng đó chỉ là khởi đầu, đặc biệt khi đa luồng phát ra. Bạn phải thêm mọi thứ vào 'hợp đồng' của hàm. Ví dụ cho const ref: phải đối tượng ở lại 'còn sống' sau khi cuộc gọi? Đối tượng có thể thay đổi trong suốt cuộc gọi không? Và kể từ đó trở đi.

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