函数重载
C++允许在同一作用域中生命几个功能类似的同名函数,这些同名函数的形参列表(参数个数、参数类型、参数顺序)必须不同,常用来处理功能类似的数据类型不同的问题。
其实函数重载很好理解,不好理解的是编译器在调用的时候是怎么区分这些同名函数的。这里就要介绍到一个概念叫名字修饰。
- 在C/C++中,一个程序运行之前要经过预处理、编译、汇编、链接这几个阶段。名字修饰是一种在编译过程中,将函数、变量的名称重新改编的机制、简单来说就是编译器通过某种算法,将函数通过某种算法,重新修饰成了一个全局唯一的名称。
- C语言中的名字修饰非常简单,编译器只是在函数名只在函数前加了一个下划线"_",因此C语言不支持函数重载
- C++中由于需要支持函数重载和命名空间,所以需要更为复杂的名字修饰,至于用什么样的方式修饰,每个编译器的做法都不同。
我们用vs作为例子 来看看名字修饰:
至于具体的修饰规则不需要去了解,因为每个编译器都不同,没必要去记,只要知道函数重载是需要名字修饰来支持,让每个重载的函数在编译期间都有唯一的全局标记就行了。
extern “C”
如果在C++工程中需要将某些函数按照C的风格来编译,就在函数前间extern “C”。
//将Add函数按照C风格来编译
extern "c" int Add(int left, int right);
//按照C风格编译,Add函数的名字修饰方式也就用的是C语言的修饰方式,所以不支持重载。
虚函数的重写
派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),就称子类的虚函数重写了基类的虚函数。
class person{
public:
virtual void Fun(int a , int,b , in t c) {
cout << "Base" << endl;
}
};
class Student: public Person{
public:
//重写基类的虚函数
virtual void Fun(int a, int b, int c) {
cout << "Student" << endl;
}
};
有两个特殊情况:
- 协变(自行了解)
- 析构函数的重写
如果基类的析构函数为虚函数,则子类只要定义虚函数,就会构成重写。这看起来违背了重写的规则,其实不然,编译器对析构函数做了特殊的处理,编译后的析构函数名称统一叫做destructor。
class Base{
public:
virtual ~Base() {cout << "~Base" << endl;}
};
class Derived{
public:
//这里的virtual要不要都可以,都会构成重写
virtual ~Derived() {cout << "~Derived" << endl}
};
重定义(同名隐藏)
基类和派生类中两个名字相同的非虚函数,那么这两个函数是重定义,在派生类中会隐藏掉基类中的重定义函数。
class Base{
public:
void Fun() {cout << "Base" << endl;}
};
class Derived{
public:
void Fun() {cout << "Derived" << endl;}
};
int main() {
Derived d;
//调用派生类中的Fun函数
d.Fun();
}