C++重载、重写、虚函数、多态
1.重载、重写、重定义
重载:在同一个类中,函数名相同,参数列表不同,编译器会根据这些函数的不同参数列表,将同名的函数名称做修饰,从而生成一些不同名称的预处理函数,未体现多态。
重写:子类重新定义父类中有相同名称相同参数的虚函数,主要是在继承关系中出现的,被重写的函数必须是virtual的,如果virtual函数是private的,子类中重写时改为public,protected也可以,体现了多态。(重写时子类函数可以不加virtual关键字,不过推荐加上)
重定义:也叫隐藏,隐藏有两种形式:
[1]派生类的函数与基类的函数完全相同(函数名和参数列表都相同),基类的函数没有使用virtual关键字。
[2]派生类的函数和基类的函数同名,但参数列表不一样,在这种情况下,不管基类的函数声明是否有virtual关键字,基类的函数都将被隐藏。(注意这种情况与函数重载的区别,重载发生在同一个类中)
2.虚函数、多态
C++的虚函数主要作用是“运行时多态”,关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”。
由于虚函数在运行时才确定,所以基类中所有的虚函数必须提供实现,而普通函数在不使用的情况下就不用实现。。
因此说多态是根据虚函数实现的,因为如果函数不是虚函数(不加virtual关键字),则子类会把基类的函数隐藏,而加上virtual后父子类的函数可以共存。
问题:
问题1:C++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。因此在派生类重新声明该虚函数时,可以加virtual,也可以不加,但习惯上一般在每一层声明该函数时都加virtual,使程序更加清晰。
多态例子:
class A
{
public:
virtual void disp(int n)
{
cout << "A::disp n=" << n << endl;
}
};
class B : public A
{
public:
void disp(int n)
{
cout << "B::disp n=" << n << endl;
}
};
int main()
{
A *p;
A a;
B b;
// 多态
p = &a;
p->disp(1);
p = &b;
p->disp(1);
return 0;
}
3.纯虚函数
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都必须要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”。
引入纯虚函数的原因:在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
声明了纯虚函数的类是一个抽象类。所以,用户不能创建类的实例,只能创建它的派生类的实例。
4.虚函数表
都知道C++中的多态是用虚函数实现的: 子类覆盖父类的虚函数, 然后声明一个指向子类对象的父类指针, 如Base *b = new Derive(); 当调用b->f()时, 调用的是子类的Derive::f()。
这种机制内部由虚函数表实现,下面对虚函数表结构进行分析。
包含虚函数的类才会有虚函数表, 同属于一个类的对象共享虚函数表, 但是有各自的_vptr,虚函数表实质是一个指针数组,里面存的是虚函数的函数指针。