2013-10-05 22 views
20

Trong đoạn mã dưới đây, hàm con trỏ và những gì tôi coi là "chức năng tham khảo" dường như có ngữ nghĩa giống hệt nhau:con trỏ hàm vs tham khảo Function

#include <iostream> 
using std::cout; 

void func(int a) { 
    cout << "Hello" << a << '\n'; 
} 
void func2(int a) { 
    cout << "Hi" << a << '\n'; 
} 

int main() { 
    void (& f_ref)(int) = func; 
    void (* f_ptr)(int) = func; 

    // what i expected to be, and is, correct: 
    f_ref(1); 
    (*f_ptr)(2); 

    // what i expected to be, and is not, wrong: 
    (*f_ref)(4); // i even added more stars here like (****f_ref)(4) 
    f_ptr(3); // everything just works! 

    // all 4 statements above works just fine 

    // the only difference i found, as one would expect: 
// f_ref = func2; // ERROR: read-only reference 
    f_ptr = func2; // works fine! 
    f_ptr(5); 

    return 0; 
} 

tôi đã sử dụng gcc phiên bản 4.7.2 trong Fedora/Linux

CẬP NHẬT

câu hỏi của tôi là:

  1. Tại sao con trỏ hàm không yêu cầu dereferencing?
  2. Tại sao dereferencing tham chiếu hàm không dẫn đến lỗi?
  3. Có (Có) có bất kỳ tình huống nào mà tôi phải sử dụng cái này qua người khác không?
  4. Tại sao f_ptr = &func; hoạt động? Vì func nên được phân rã thành một con trỏ?
    Trong khi f_ptr = &&func; không hoạt động (chuyển đổi ngầm từ void *)

Trả lời

10

Chức năng và tài liệu tham khảo chức năng (ví dụ id-biểu của những loại) sâu vào con trỏ chức năng gần như ngay lập tức, vì vậy các biểu thức funcf_ref thực sự trở thành con trỏ hàm trong trường hợp của bạn. Bạn cũng có thể gọi (***func)(5)(******f_ref)(6) nếu muốn.

Có thể thích hợp hơn khi sử dụng tham chiếu hàm trong trường hợp bạn muốn & -operator hoạt động như thể nó đã được áp dụng cho chính hàm đó, ví dụ: &func giống với &f_ref, nhưng &f_ptr là thứ khác.

+0

là lỗi triển khai? 'coz mà đi ngược lại các khái niệm trực quan của chúng ta về "đánh máy", phải không? Tôi cũng đã nhìn thấy một cái gì đó như 'void (* & f) (void)' như là một tham số để chức năng - '*' và '&' được sử dụng cùng nhau .. làm thế nào đến? – John

+0

Nó không phải là một lỗi, chỉ là cách ngôn ngữ được xác định. Trong các biểu thức, về cơ bản không có hàm, chỉ có các con trỏ hàm; phân rã chăm sóc làm cho cú pháp "rõ ràng" hoạt động (tức là bạn có thể gõ 'f (1)' thay vì 'cồng kềnh' (& f) (1) '). –

+0

@John: So sánh với cách mảng được xử lý; chúng _can't_ được truyền bởi giá trị, vì vậy trong một prototype mẫu, 'int x []' (và cho rằng vấn đề ('int x [10]') tương đương với 'int * x'; vì nhận được một mảng C bởi giá trị không hợp lệ, chúng cho phép cú pháp khai báo mảng được sử dụng như cú pháp đường để nhận con trỏ. – ShadowRanger

2

Xem here.

Toán tử địa chỉ hoạt động như bạn mong đợi, vì nó trỏ đến một hàm nhưng không thể được chỉ định. Các hàm được chuyển đổi thành con trỏ hàm khi được sử dụng làm giá trị, có nghĩa là bạn có thể dereference một con trỏ hàm bất kỳ số lần nào và nhận lại con trỏ hàm tương tự.

9

"Tại sao con trỏ hàm không yêu cầu dereferencing?"

Bởi vì định chức năng riêng của mình thực sự là một con trỏ đến chức năng đã:

4,3 Chức năng-to-con trỏ chuyển đổi
§1 Một vế trái của chức năng loại T thể được chuyển đổi để một giá trị của loại "con trỏ đến T." Kết quả là một con trỏ đến hàm.

"Tại sao tham chiếu chức năng tham chiếu không dẫn đến lỗi?"

Về cơ bản, bạn có thể xem xét xác định tham chiếu là xác định bí danh (tên thay thế).Tham khảo 8.3.2 Tham khảo một phần giải quyết việc tạo tham chiếu đến đối tượng, bạn sẽ tìm thấy:
"tham chiếu có thể được coi là tên của đối tượng".

Vì vậy, khi bạn định nghĩa một tài liệu tham khảo:

void (& f_ref)(int) = func; 

nó mang lại cho bạn khả năng sử dụng f_ref gần như ở khắp mọi nơi mà nó sẽ có thể sử dụng func, đó là lý do tại sao:

f_ref(1); 
(*f_ref)(4); 

hoạt động chính xác giống như cách sử dụng trực tiếp func:

func(1); 
(*func)(4); 
Các vấn đề liên quan