Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

Название mangling.

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

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

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

func_foo_int_float_char()

(реальный символ обычно является некоторым gobbledygook как [email protected]@@[email protected]).

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

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

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

Ответ 2

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

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

Ответ 3

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

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

objectInstance->function("Hello World")  

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

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

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

Ответ 4

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

Ответ 5

Это, я считаю, достигается с помощью обработки имени:

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

Ответ 6

Функциональная подпись состоит из имени функции + параметра (ов)

Ответ 7

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

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

Ответ 8

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

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

создаст имена символов __Z4testi, __Z4testff, __Z4testd, __Z7testbamd. Это изменение имени сильно зависит от компилятора (к сожалению) и одна из многих причин, почему часто C предпочтительнее, чем С++.

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