В C ++, как обычно осуществляется перегрузка функций? - PullRequest
17 голосов
/ 09 февраля 2010

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

Ответы [ 8 ]

12 голосов
/ 09 февраля 2010

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

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

11 голосов
/ 09 февраля 2010

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

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

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

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

func_foo_int_float_char()

(реальным символом обычно является какая-то болтовня вроде ?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

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

6 голосов
/ 09 февраля 2010

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

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

objectInstance->function("Hello World")  

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

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

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

3 голосов
/ 09 февраля 2010

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

0 голосов
/ 09 февраля 2010

Компиляторы 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 компилятор сопоставляет данные типы аргументов и количество аргументов с каждой перегрузкой функции. Затем используются прототипы функций, чтобы выяснить, какой из них следует вызывать.

0 голосов
/ 09 февраля 2010

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

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

0 голосов
/ 09 февраля 2010

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

0 голосов
/ 09 февраля 2010

Это, я считаю, достигается путем искажения имени:

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

...