В C++, как перегрузка функции обычно реализуется?

Если нет никакой перегрузки функции, имя функции служит адресом функционального кода, и когда функция вызывается, ее адрес легок найти использование ее имени. Однако с перегрузкой функции, как точно программа может найти корректный функциональный адрес? Существует ли скрытая таблица, подобная виртуальным таблицам, который снабжает перегруженные функции их адресом? Большое спасибо!

17
задан Rick 9 February 2010 в 07:46
поделиться

8 ответов

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

Обновление: удалила мою попытку проиллюстрировать концепцию, показывая функции с разными именами, между которыми компилятор может выбирать.

12
ответ дан 30 November 2019 в 12:43
поделиться

Имя искажается .

Все сделано во время компиляции. На самом деле компилятор C++ модифицирует внутри себя имена функций, которые вы даете, так что функция типа

int foo(int a, float b, char c) 

внутри получает имя, эквивалентное

func_foo_int_float_char()

(реальным символом обычно является какой-нибудь gobbledygook типа ?CFoo@Foo@@QAAX_N@Z ).

Как видите, название украшается в зависимости от точного количества и типов передаваемых параметров. Таким образом, при вызове функции компилятору легко посмотреть на передаваемые параметры, украсить ими имя функции и придумать правильный символ. Например,

int a, b; float f; char c;
foo(a,f,c) ; // compiler looks for an internal symbol called func_foo_int_float_char
foo(a,b,c) ; // compiler looks for a symbol called func_foo_int_int_char

Опять же, все это делается полностью во время компиляции.

11
ответ дан 30 November 2019 в 12:43
поделиться

Если вы говорите о перегруженных методах одного и того же класса, например:

void function(int n);
void function(char *s);
...

objectInstance->function("Hello World")  

Это штука времени компиляции. Компилятор знает (а в некоторых ситуациях лучше всего угадывает), какой метод вызывать.

Комментарий, который я сделал в вопросе, повторяю здесь.

Люди, которые предлагают искажение имени, думаю, ошибаются. Это не так, как если бы компилятор искажает имя и просто ищет среди искаженных имен. Он должен сделать вывод о правильных типах из доступных методов. Как только он это делает, он уже знает, какой метод вызывать. Затем он использует искаженное имя в качестве последнего шага . Искажение имени не является обязательным условием для определения, какую перегруженную функцию вызывать.

6
ответ дан 30 November 2019 в 12:43
поделиться

Перегруженные функции разрешаются во время компиляции. Компилятор находит подходящее соответствие для заданного набора параметров и просто вызывает соответствующую функцию по ее адресу ( void foo (int) и void foo () практически две полностью независимые функции. - если в вашем коде есть foo (4) , компилятор знает, какую функцию вызывать).

3
ответ дан 30 November 2019 в 12:43
поделиться

Я полагаю, это достигается путем изменения имени:

функции, которые вы знаете как foo (int) и foo (double), на самом деле называются как-то как int_foo () и double_foo () (или аналогичные, я не совсем уверен в конкретной семантике, используемой для C ++). Это означает, что символы C ++ обычно на порядок больше, чем имена, которые им даны в коде.

0
ответ дан 30 November 2019 в 12:43
поделиться

Даже при отсутствии перегрузки функций компиляторы обычно искажают имена функций и переменных. Это называется искажением имени . Это происходит как в C, так и в C ++. Имя функции может быть оформлено, в частности, (1) соглашением о вызовах, (2) перегрузкой функций C ++, (3) функцией-членом класса.

GNU binutil c ++ filter может удалить это искаженное имя, а в Windows есть UnDecorateSymbolName

-1
ответ дан 30 November 2019 в 12:43
поделиться

Сигнатура функции состоит из имени функции + тип(ы) параметра(ов)

.
-1
ответ дан 30 November 2019 в 12:43
поделиться

C ++ компиляторы используют изменение имен (разные имена для каждой перегрузки), чтобы различать функции в объектном файле. Например,

int test(int a){}
int test(float a,float b){}
int test(double a){}
int testbam(double a){}

создаст имена символов __ Z4testi , __ Z4testff , __ Z4testd , __ Z7testbamd . Это искажение имен сильно зависит от компилятора (к сожалению) и является одной из многих причин, почему часто C предпочтительнее C ++.

При вызове функции test компилятор сопоставляет заданные типы аргументов и количество аргументов для каждой перегрузки функции. Затем прототипы функций используются для определения того, какой из них следует вызвать.

-1
ответ дан 30 November 2019 в 12:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: