如果没有函数重载,函数名称将作为函数代码的地址,并且在调用函数时,可以使用其名称轻松查找其地址。但是对于函数重载,程序究竟能找到正确的函数地址吗?是否存在类似于虚拟表的隐藏表,用于存储带有地址的重载函数?非常感谢!
答案 0 :(得分:12)
编译器可以查看调用,并将其与已知的现有重载实现进行匹配,然后选择正确的实现。不需要动态表,它在编译时静态完全可行。
更新:通过显示编译器可以选择的不同命名的函数,删除了我尝试说明概念的尝试。
答案 1 :(得分:11)
这一切都是在编译时完成的。 C ++编译器实际上修改了你在内部给它的函数名,所以像
这样的函数int foo(int a, float b, char c)
在内部获得一个等同于
的名称func_foo_int_float_char()
(真正的符号通常是像?CFoo@Foo@@QAAX_N@Z
一样的gobbledygook。)
如您所见,根据传递的参数的确切数量和类型来装饰名称。因此,当您调用函数时,编译器很容易查看您传递的参数,使用它们修饰函数名称,并提供正确的符号。例如,
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 :(得分:6)
如果您正在讨论同一类的重载方法,请执行以下操作:
void function(int n);
void function(char *s);
...
objectInstance->function("Hello World")
这是编译时间的事情。编译器知道(或在某些情况下,做出最佳猜测)此时调用哪种方法。
我在问题中提出的评论,我在这里重复。
我认为,建议改名的人是错误的。这并不是说编译器破坏了名称,只是在错位名称之间进行查找。它需要从可用的方法推断出正确的类型。一旦它这样做,它已经知道要调用哪种方法。然后,它使用损坏的名称作为 last 步骤。名称修改不是确定要调用哪个重载函数的先决条件。
答案 3 :(得分:3)
重载函数在编译时解析。编译器为给定的参数集找到合适的匹配,并简单地通过其地址调用相应的函数(void foo(int)
和void foo()
实际上是两个完全独立的函数 - 如果你的foo(4)
中有{{1}}代码,编译器知道要调用哪个函数。
答案 4 :(得分:0)
我认为,这是通过名称修改实现的:
你知道的函数foo(int)和foo(double)实际上被命名为int_foo()和double_foo()(或类似的,我不完全确定C ++使用的特定语义)。这意味着C ++符号通常比代码中给出的名称大一个数量级。
答案 5 :(得分:-1)
函数签名由函数名+参数类型
组成答案 6 :(得分:-1)
即使没有函数重载,编译器通常会破坏函数和变量名。它被称为 name mangling 。它发生在C和C ++中。函数名可以通过(1)调用约定,(2)C ++函数重载,(3)类成员函数进行修饰。
GNU binutil c++filt
可以解包这个受损的名称,在Windows中,有UnDecorateSymbolName
答案 7 :(得分:-1)
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
时,编译器会针对每个函数重载匹配给定的参数类型和参数数。然后使用函数原型来找出应该调用哪一个。