https://www.cnblogs.com/lsgxeva/p/7684545.html
https://blog.csdn.net/K346K346/article/details/49386747
首先抛一些结论:
重载
- 发生在同一作用域
- 具有相同的函数名及不同的参数列表
- 对返回值不做要求,可相等可不等
重写(覆盖)
- 发生在基类与派生类之间,在不同作用域
- 具有相同的函数名、参数列表、返回类型(关于返回类型存在一种特殊情况,即返回类型可以不用完全一致,协变返回类型(covariant return type)也可以构成虚函数重写。)
隐藏
- 发生在不同作用域
- 可以是派生类成员函数隐藏基类成员函数,也可以是类成员函数隐藏全局外部函数
- 重写是隐藏的一种特例
- 被隐藏的函数没有消失,仍然可以通过指定作用域访问它们
代码
#include <iostream>
using namespace std;
void func(const char* s)
{
cout << "global function with name:" << s << endl;
}
class A
{
void func()
{
cout << "member function of A" << endl;
}
public:
void useFunc()
{
//func("lvlv");//A::func()将外部函数func(char*)隐藏
func();
::func("lvlv");
}
virtual void print()
{
cout << "A's print" << endl;
}
};
class B :public A
{
public:
//隐藏A::vodi useFunc()
void useFunc()
{
cout << "B's useFunc" << endl;
}
//隐藏A::vodi useFunc()
int useFunc(int i)
{
cout << "In B's useFunc(),i=" << i << endl;
return 0;
}
virtual int print(const char* a)
{
cout << "B's print:" << a << endl;
return 1;
}
virtual int print(int a)
{
cout << "B's print:" << a << endl;
return 1;
}
//下面编译不通过,因为对父类虚函数重写时,需要函数返回值类型,函数名称和参数类型全部相同才行
// virtual int print()
//{
// cout<<"B's print:"<<a<<endl;
//}
//可以这样理解:函数名和参数列表是编译器认识函数的凭证。
//编译器看到print及参数列表, 认为程序员想进行重写,但是此时返回值不一致,不可构成重写,因此编译不通过
};
int main()
{
A a;
a.useFunc();
B b;
b.useFunc();//A::useFunc()被B::useFunc()隐藏
b.A::useFunc();
b.useFunc(2);
//b.print();//编译出错,A::print()被B::print(char* a)隐藏
b.A::print();
b.print("jf");
b.print(1);//类内重载,并且隐藏了基类print
}
以上代码使用b.A::useFunc();
和::func("lvlv");
访问了被隐藏的基类成员函数和类外的普通函数
值得注意的是,当派生类成员函数的函数名+参数列表与基类成员的virtual函数一致时,若返回值不同,则会编译失败。
这里涉及到协变,可以参考
https://www.cnblogs.com/lsgxeva/p/7684545.html
小结
在理解重载、重写、覆盖的区别时,私以为作用域是很重要的切入点,这三个概念不相同但也不互斥,存在并不复杂的相交关系、包含关系。