前几天面试时被问及C++中的覆盖、隐藏,概念基本答不上来,只答了怎么用指针实现多态,也还有遗漏。最终不欢而散。回来后在网上查找学习了一番,做了这个总结。
概念
一、重载(overload)
指函数名相同,但是它的参数表列个数或顺序,类型不同。但是不能靠返回类型来判断。
(1)相同的范围(在同一个作用域中) ;
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
(5)返回值可以不同;
二、重写(也称为覆盖 override)
是指派生类重新定义基类的虚函数,特征是:
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有 virtual 关键字,不能有 static 。
(5)返回值相同(或是协变),否则报错;<—-协变这个概念我也是第一次才知道…
(6)重写函数的访问修饰符可以不同。尽管 virtual 是 private 的,派生类中重写改写为 public,protected 也是可以的
三、重定义(也成隐藏)
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)函数名字相同;
(3)返回值可以不同;
(4)参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载以及覆盖混淆) 。
(5)参数相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 。
例子
#include <iostream>
using namespace std;
class SParent
{
public:
SParent( ){};
SParent( const SParent &p )
{
cout << "parent copy construct" << endl;
}
int add( int a,int b )
{
cout << "parent int add" << endl;
return a + b;
}
double add( double a,double b )
{
cout << "parent double add" << endl;
return a + b;
}
virtual int dec( int a,int b )
{
cout << "parent int dec" << endl;
return a - b;
}
};
class SChild : public SParent
{
public:
//using SParent::add;
float add( float a,float b )
{
cout << "child float add" << endl;
return a + b;
}
int dec(int a, int b)
{
cout << "child int dec" << endl;
return a - b;
}
};
int main()
{
/* 测试重载 */
SParent parent;
parent.add( 3,5 );
parent.add( (double)3,(double)5 );
cout << endl;
/* 测试覆盖 */
SChild *pchild = (SChild *)new SParent();/* 基类强转为子类...危险...,用dynamic_cast转换也不行 */
pchild->dec( 10,3 );
SParent *pparent = new SChild();
pparent->dec( 11,3 );
cout << endl;
/* 测试隐藏 */
SChild child;
child.add( (int)3,(int)5 );
cout << endl;
/* 测试函数表 */
((SParent *)NULL)->add( 4,6 );
((SChild *)NULL)->add( 4,6 );
int a = 0;
((SChild *)&a)->add( 4,6 );
cout << endl;
/* 测试函数地址 */
((SParent)child).add( (int)4,(int)8 );
child.SParent::add( 3,5 );
return 0;
}
输出结果:
parent int add
parent double add
parent int dec
child int dec
child float add
parent int add
child float add
child float add
parent copy construct
parent int add
parent int add
按 <RETURN> 来关闭窗口...
理解
int SParent::add(int a,int b)与double SParent::add( double a,double b )是重载
int SParent::add(int a,int b)与double SParent::add( double a,double b )都被子类SChild中的float SChild::add( float a,float b )隐藏
int SParent::dec( int a,int b )被子类SChild中的int SChild::dec( int a,int b )覆盖
测试
1.重载测试,简单易懂,略过。
2.覆盖测试。dec函数在基类、子类中同名同参,为虚函数,故称覆盖。
SChild *pchild = (SChild *)new SParent()创建的是一个基类对象,其函数表应该为
SParent *pparent = new SChild();创建一个子类对象,其函数表应该为