C++中重载、覆盖和多态是三个有些相似的概念,以下以代码的方式展示三者的不同。
1)重载:同名函数不同参数(类型、个数),编译时编译器确定使用哪个函数,属于编译时“多态”,不是真正的多态;
2)覆盖:子类覆盖父类的虚函数,函数名、参数必须相同。覆盖需要满足两个条件,继承父类的虚函数和使用父类的指针(或引用)绑定子类实例。由覆盖产生的多态是运行时多态,编译时无法确定具体调用那个函数,是真正的多态;
3)隐藏:父类与子类中同名函数的一种处理机制,同一个子类的函数可以同时覆盖父类的函数并且隐藏父类的某些函数。
/**这个工程主要研究C++中的重载、覆盖和隐藏三个相似的概念*/
#include <iostream>
#include <string>
using namespace std;
void fun(int i)
{
cout << "int: " << i << endl;
}
//int fun(int i) //错误,不能根据返回值来对函数进行重载!
//{
// cout << i << endl;
//}
void fun(float i)
{
cout << "float: " << i << endl;
}
void fun(int *p)
{
cout << "pointer: " << *p << endl;
}
void fun(const int *p) //正确,low level的const可以作为重载的依据!
{
cout << "const pointer: " << *p << endl;
}
//void fun(int* const p) //错误,top level的const不能作为重载依据!
//{
// cout << *p << endl;
//}
class Base
{
public:
virtual void fun1(int i)
{
cout << "Base int: " << i << endl;
}
void fun1(float i) //与上一个fun1构成重载关系
{
cout << "Base float: " << i << endl;
}
void fun2(int i, int j)
{
cout << "Base i j: " << i + j << endl;
}
};
class Derived : public Base
{
public:
void fun1(int i) override //覆盖了virtual void fun1(int i),同时隐藏了void fun1(float i);override(C++11)关键字保证该函数覆盖了父类的某个函数!
{
cout << "Derived int: " << i << endl;
}
void fun1(string str) //隐藏了父类的fun1,并且与子类的fun1形成重载
{
cout << "Derived string: " << str << endl;
}
void fun2(float i) //隐藏了父类的fun2
{
cout << "Derived float: " << i << endl;
}
};
int main()
{
/**1: 重载,重载的概念比较简单,函数名相同,参数类型(或个数)不同即可构成重载。
但重载要注意两点,第一函数返回值不能作为重载依据,第二top-level的const不能作为重载依据。
top-level的const指对象本身是const,而low-level的const值该对象指向的对象是const。
重载的根本依据就是编译器是否可以根据函数的参数来区分不同的函数。*/
int i = 0, *p = &i;
const int *cp = &i;
float f = 0.5;
fun(i);
fun(f);
fun(p);
fun(cp);
/**2: 覆盖,覆盖发生在子类与父类之间。覆盖必须满足1)父类定义virtual函数;2)子类中有同名、同参数函数。
覆盖于重载的重要区别是重载是编译时“多态”,而覆盖是运行时多态(真正的多态),也就是说只有在运行时
才能确定使用哪个函数。*/
Base b;
b.fun1(1);
Derived d;
d.fun1(1);
Base &bd = d;
bd.fun1(1);
/**3: 隐藏,隐藏也发生在子类和父类之间。子类与父类的同名函数到底是隐藏还是覆盖由两点决定:
1)无virtual,同名即隐藏(无论参数相同或不同);
2)有virtual,同名不同参数是隐藏,同名相同参数是覆盖。*/
d.fun1(0.5); //无法调用父类的float的版本,只能调用子类的int版本!
d.fun1("abc");
//d.fun2(1, 2); 错误,子类的fun2隐藏了父类的fun2,无法使用父类的fun2!
d.Base::fun2(1, 2); //可以显示的调用父类的函数。
return 0;
}