2015-11-04 2 views
5

Я знаю, когда мы используем имя функции как значение, функция автоматически преобразуется в указатель. посмотреть на следующий код:назначение указателя функции и вызов в C++?

int print(int a) 
{ 
    return a; 
} 

int main() 
{ 
    int (*p)(int) = print; 
    int (*q)(int) = &print; 

    cout << p(8) << endl; 
    cout << (*p)(8) << endl; 
} 

почему int (*p)(int) = print;, печать является указателем, и int (*p)(int) = &print;, & печати является обращение к указателю, эквивалент?

С другой стороны, когда мы используем указатель на функцию для вызова функции, почему p(8) и (*p)(8) эквивалент?

+0

Я предполагаю, что это просто для удобства , что вам не нужно явно указывать указатели на функции при их использовании для вызова функции. Если вы используете 'typedefs', вы можете работать с указателем функции, не используя никаких' * ', которые imho довольно приятны. – user463035818

+2

Возможный дубликат [Как происходит разыменование указателя функции?] (Http://stackoverflow.com/questions/2795575/how-do-dereferencing-of-a-function-pointer-happen) –

+0

@SimonKraemer спасибо. Но ссылка только объясняет разницу, мой вопрос также включает назначение указателя функции. – sydridgm

ответ

2

print является функцией, но это неявное преобразование к типу указателя на функцию. Цитируется cppref:

Функция указатель
Именующего выражение типа функции T может быть неявно преобразуется в prvalue указатель на эту функцию. Это не относится к к нестационарным функциям-членам, поскольку lvalues, которые относятся к , нестатические функции-члены не существуют.

Таким образом, в вашем случае:

int (*p)(int) = print; // Conversion happens. 
int (*q)(int) = &print; // Conversion does not happen. 

пинки неявного преобразования автоматически, когда это необходимо, чтобы сделать программу компиляции, и не применяется в противном случае.

Что касается вызова функций, то речь идет о встроенном вызове функции вызова (). Согласно cppref, встроенный оператор вызова функции применим как к выражению lvalue, которое относится к функции, так и к указателю на функцию. В вашем случае:

p(8); // The function call operator is applied to a pointer to function. 
(*p)(8); // The function call operator is applied to an lvalue reference to function. 

Для справки (курсив мой):

выражение оператор
вызов функции Встроенный вызов функции, такие как E (A1, A2, A3) , состоит из выражения , которое называет функцию E, а затем, возможно, пустым список выражений A1, A2, A3, ... в скобках.Выражение , что имена функция может быть

а) именующего выражения, которое относится к функции
б) указателя на функцию
...

3

print является не указатель. Его тип: int(int), а не int(*)(int). Это различие особенно важно в типе дедукции

auto& f = print; //type of f is int(&)(int), not int(*(&))(int) 
template<typename Func> 
foo(Func& f); 
foo(print); //Func is deduced to be int(int), not int(*)(int) 

По аналогии с массивами, вы не можете скопировать функцию «по значению», но вы можете обойти его адрес. Например,

int arr[4];  //the type of arr is int[4], not int* 
int *a = arr; //automatic array-to-pointer decay 
int (*a)[4] = &arr; //type match 
int (*p)(int) = print; //automatic function-to-pointer decay 
int (*p)(int) = &print; //type match 

Теперь, когда вы звоните print через p,

p(8)  //automatic dereferencing of p 
(*p)(8) //manual dereferencing of p 
+0

ваш ответ имеет смысл. но в книге ** C++ primer 5th edition ** и во многих других учебниках по сайту сказано, что с помощью имени функции rvalue преобразует ее в указатель. Поэтому я не знаю, является ли ваш ответ особым условием назначения указателя функции. – sydridgm

+0

@sydridgm Они правильные. И они ссылаются на разложение функции-на-указатель в моем ответе. – downhillFromHere

Смежные вопросы