重载
重载:同一个作用域里面,两个函数它的函数名是一样的,但是参数的类型或者个数是不一样的。
因为实际上,编译器会对函数名进行重写, 根据它的参数的类型和个数,给它一个新的函数名,所以在编译器看来,这两个函数它还是一个不同的函数吧。
tips: 只有形参类型or个数不一样,才能重载,不关返回类型的事情
隐藏
这个跟名字查找有关系,c++是先在自己静态类型的作用域查找名字,找到就不找了(然后执行类型检查),找不到再往外层作用域一步步查找,所以简单说就是:
内层作用域的一个叫 fcn的函数,隐藏掉了外层作用域的 fcn函数 (不管形参类型,返回类型这些乱七八糟的是不是一样)
比如:子类中的函数会使得父类的所有同名函数都被隐藏。
可以通过base_name::func_name的方式访问基类同名函数
覆盖
覆盖专指虚函数的覆盖。子类重新定义了父类中的虚函数。(这里它跟基类的虚函数 必须返回类型啊,形参类型啊都完全有一个,有一个特例 见c++prime 537),覆盖的同时 肯定也起到了隐藏的作用,所以说覆盖是隐藏的特例。
class Base {
public:
virtual void fcn() {
cout << 1 << endl;
}
void fcn(int i) {
cout << 2 << endl;
}
//private: (1)
// void fcn(string s) {
// cout << "hh" << endl;
// }
};
};
class Derived :public Base {
public:
//using Base::fcn; (2)
void fcn() {
cout << 3 << endl;
}
};
int main() {
Derived d;
d.fcn(); //3
d.fcn(1); //error 隐藏掉了 (3)
system("pause");
}
假如(1)(2) 都注释 那(3)error
using Base::fcn 可以把Base 中的所有重载fcn都给加到我的Derived 里面 ,加到Derived的public部分 就都是public 加到private 就都是private , 不过注意有个坑,就是 基类的fcn 必须对 派生类都是可访问的,不然gg
比如我把(1)(2)都不注释,那Base 的private 有一个fcn,那using Base::fcn 编译的时候就error了
再一个就是 (1)注释 (2) 不注释 那我的 (3) 就对了 输出的是2
也就知道了,我们可以用 using 把基类的 fcn 都给加进来 ,然后 我再重新定义里面 我想要的重新定义的部分函数
1)函数覆盖是虚函数覆盖(也不是,非虚函数也能覆盖,条件也是下面两个2条件),要想发生函数覆盖,必须 1. 函数签名(函数名称+参数个数+参数类型)一样 2. 返回类型一样。
两条件缺一不可,你缺了一个(一般容易引起误解的就是,返回类型这一块),那就是在派生类声明了一个非虚函数(因为一般不会加 virtual),同时还隐藏了基类中的所有重载同名虚函数。
对于条件2,有 个特例,prime p537,说了当返回类型,在基类中是基类的指针or引用,而在派生类中是派生类的指针or引用,那也是函数覆盖!
2)函数覆盖,必定伴随着函数隐藏,因为覆盖是隐藏的特例,所以,假如基类有两个重载的虚函数,你在派生类只针对其中一个覆盖了,那你也隐藏了外部作用域的那两个虚函数。
3)隐藏只是让这个函数的可访问性gg,并没有实质的删除这个函数,另外有一点,函数匹配,先找最佳匹配,最后检查可访问性
有个例子针对前半句的,我在A 定义了一个virtual 函数 fun,然后 B public继承了A ,但是他隐藏了而不是覆盖了fun,然后C public继承了B,在C里面我们还是能覆盖,就是重新写一个fun来覆盖那个virtual fun,也就是我在C里面写了一个fun跟A的fun,参数,返回类型一样的函数,虽然我没声明,但是它是一个虚函数!