重载、重写、重定义的区别:
重载
在一个类中的重名函数,由于函数参数个数/类型的不同(形参列表不同),导致使用不同的函数进行处理,这种情况称为重载
。
class A
{
public:
void show(){
cout << "show()" << endl;
}
void show(int x){
cout << "show(int x):"<< x << endl;
}
};
int main(){
A a;
a.show();
a.show(3);
}
对于重载函数,想调用哪个函数,取决于你给的参数。运行结果如下:
重定义(隐藏)
情况一
- 如果同名函数在不同的类中,则他们不再是重载函数,
- 若他们的形参列表不同,则基类中的同名函数将被隐藏(屏蔽)
class A
{
public:
void show(){
cout << "A--show()" << endl;
}
};
class B : public A
{
public:
void show(int x){
cout << "B--show()" << x << endl;
}
};
int main(){
B a;
//a.show();
//此时基类中的show()和子类中的函数同名而参数不同,
//满足隐藏的条件,子类从基类继承而来的没有参数的
//show()已经被隐藏了,无法调用
a.A::show();
a.show(5);
system("pause");
return 0;
}
情况二
- 同名函数在不同的类中、参数相同,且基类中的同名函数前没有virtual关键字声明,那么基类中的同名函数依然会被隐藏。
class A
{
public:
/* virtual */void show(){
cout << "A--show()" << endl;
}
};
class B : public A
{
public:
void show(){
cout << "B--show()" << endl;
}
};
int main(){
B a;
a.show();
system("pause");
return 0;
}
class A
{
public:
/* virtual */void show(){
cout << "A--show()" << endl;
}
};
class B : public A
{
public:
};
int main(){
B a;
a.show();
system("pause");
return 0;
}
对照上边两个程序:
- 当子类中有与基类同名的参数,并且没有
virtual
修饰就构成隐藏 - 当子类中拥有与父类相同函数名的函数时,子类对象在调用该函数时,会首先去子类中查找实现方式,如果子类中有实现,则执行子类函数,如果子类函数没有实现,然后去调用父类函数。
重写(覆盖)
- 如果同名函数在不同的类中、参数相同、基类中的同名函数带有virtual关键字声明,这时基类中的同名函数将被重写(覆盖),它有以下两个特点:
①当对象调用子类中的同名函数时,表现和被隐藏时相同,程序结果不变(但其实和隐藏是不同的);
class A
{
public:
virtual void show(){
cout << "A--show()" << endl;
}
};
class B : public A
{
public:
void show(){
cout << "B--show()" << endl;
}
};
int main(){
A a;
B b;
a.show();
b.show();
system("pause");
return 0;
}
②当通过指针或引用调用子类中的同名函数时,由于需要区别指针(引用)的类型和指针(引用)所指对象的类型,此时的表现就和隐藏不同了——通过基类指针指向不同对象,指针会根据对象的类型不同,调用其相应的函数。
class A
{
public:
virtual void show(){
cout << "A--show()" << endl;
}
};
class B : public A
{
public:
void show(){
cout << "B--show()" << endl;
}
};
void fun(A* p){
p->show();
}
int main(){
A a;
B b;
fun(&a);
fun(&b);
system("pause");
return 0;
}
一个含有虚函数的类中都至少都有一个虚函数表指针,因为虚函数的地址要被放到虚函数表中, 虚函数表也简称虚表。
运行结果: