函数重载在哪里进行?
在创建程序的过程中,比如编译器、链接器等,函数重写和运算符重载是在什么地方进行的呢?
我特别想知道在C++、Ruby和Python中,这些操作是在哪里完成的。
3 个回答
Python 不是通过链接或编译的方式运行的,而是通过解释的方式。
所以,当类的源代码被解析时,通常会进行正常的重写。当然,由于 Python 的动态特性,你也可以在运行时随时进行重写。
我想,使用字节码编译的其他实现方式是在编译时进行的。
我觉得 Ruby 也是这样。
在C++中,运算符重载是在编译器层面完成的,具体是通过一种叫做“名称改编”的过程来实现的。这个过程会为每个函数创建一个独特的名字标识符,这样链接器就不会因为函数定义重复而报错。简单来说,C++允许我们重载运算符,比如 +
、-
、*
等,因为这些运算符实际上也是函数,它们的名字前面都有一个 operator
的前缀,后面跟着运算符的符号。例如,一个重载的 operator+
函数,如果它的函数签名是
my_type operator+(const my_type& lhs, const my_type& rhs);
那么它和另一个不同签名的 operator+
函数不会冲突。虽然这两个函数的名字都是 operator+
,但在C++编译器完成名称改编后,它们在汇编语言层面会有不同的名字。因此,名称改编还有一个好处,就是可以让C和C++编译的代码使用同一个链接器,因为两个同名的函数不会同时存在,从而避免链接错误。
需要注意的是,在C语言中,即使你创建了两个不同签名的函数,如果它们的名字相同,由于C编译器不会进行名称改编,链接器就会因为函数定义重复而报错。
函数重载(在C++中)是由编译器内部处理的。简单来说,就是编译器会生成特定的代码,直接调用合适的函数,就好像这些函数都有不同的名字一样,你调用的函数正好适合你传入的参数。一般来说,在大多数支持重载的编译语言中,重载的解析是在编译时完成的,生成的代码总是会调用指定的函数。例如,Haskell就是通过这种方式支持编译时重载的。
运算符重载是一般重载的一个特殊情况,所以通常也是以相同的方式处理。
函数重写(这个术语出现在面向对象编程中,当一个派生类继承自基类并重新定义其中一个方法时)几乎总是在运行时解决的,因为编译器并不能总是知道哪个函数会被调用,除非它在运行时了解类型。有些编译器可能能够静态地证明某个对象具有特定类型,从而优化掉动态调用,但这并不是在所有情况下都能做到的。
我不知道有没有支持重载的动态语言,因为理论上你可以在程序运行时引入新的重载候选。如果有这样的语言,我很想了解一下。