多态存在的问题
虚函数主要用于c++中的多态特性,对于类的继承而言,如果用父类的指针指向子类的的对象,当用该指针操作子类对象时,该指针只能操作父类中的函数,而对于子类中特有的和重载的方法,用该指针将无法使用。案例:
class Base {//基类
public:
void test()
{
cout << "A" << endl;
}
};
class Derive :public Base{//派生类
public:
void test()//派生类重载基类的test()
{
cout << "B" << endl;
}
void show()//派生类独有的方法
{
cout << "show" << endl;
}
}
int main()
{
Base a;
Derive d;
//p1 p2均为Base类的指针
Base* p1 = &a;//p1指向Base类对象
Base* p2 = &d;//p2指向Derive类的对象
p1->test();//正确。调用A
p2->test();//调用Base类的test()
p2->show();//编译错误,“Base中没有成员show()”
}
虚函数拟要解决的问题
虚函数可以解决用父类的指针访问子类中重载父类的函数上面案例的做出如下修改:
class Base {//基类
public:
virtual void test()
{
cout << "A" << endl;
}
};
class Derive :public Base{//派生类
public:
virtual void test()//派生类重载基类的test()
{
cout << "B" << endl;
}
void show()//派生类独有的方法
{
cout << "show" << endl;
}
}
int main()
{
Base a;
Derive d;
//p1 p2均为Base类的指针
Base* p1 = &a;//p1指向Base类对象
Base* p2 = &d;//p2指向Derive类的对象
p1->test();//正确。调用A
p2->test();//调用Derive类的test()
p2->show();//编译错误,“Base中没有成员show()”
}
在需要重载的方法前面加上virtual关键字,就可以用父类的指针调用子类的重载方法。当基类中用虚函数时,其派生类在重载该虚函数时也是用虚函数的方式进行重载,重载虚函数时其关键字virtual可以省略,但是为了更直观不建议省略。 进行虚函数重载时函数的参数和返回类型必须和原来父类的函数一样。上述规则在有种情况下是不成立的,当函数返回的是类本身的指针或者引用。例子如下:
class Base {
public:
virtual Base * clone()
{
Base* p = new Base;
return p;
}
virtual void show()
{
cout << "test Base" << endl;
}
};
class Derive :public Base{
public:
virtual Derive* clone()
{
Derive* p = new Derive;
return p;
}
void show() {
cout << "test Derive" << endl;
}
};
int main()
{
Base a;
Derive d;
Base* p1 = a.clone();//调用基类的clone()函数
Base* p2 = d.clone();//调用派生类的clone()函数
p1->show();
p2->show();
delete p1;
delete p2;
}
final和override
虚函数重载时,如果参数和基类的参数不同则编译器将会认为该函数为派生类的独有的函数,为了能够知道派生类是否正确的覆盖了虚函数,C++中引入了关键字override,用以检查派生类是否正确的覆盖了虚函数。
只有虚函数的覆盖才能在函数的后面加上override(加到参数列表、const、&符的后面)
当某个虚函数后面被加上final关键字后,表示该函数将不能够被覆盖,如果覆盖这样的虚函数则编译器将会报错。
虚函数的默认参数
虚函数中同样可以定义默认参数,但是对于派生类而言,如果派生类的对象掉用虚函数时使用到了默认参数,那么该默认参数将会是基类的默认参数。
class Base {
public:
virtual void show(int i=0)
{
cout << i << endl;
}
};
class Derive :public Base{
public:
void show(int i=1)
{
cout << i << endl;
}
};
Base a;
Derive d;
a.show();//打印结果为0
b.show();//打印结果为0,派生类的默认值为基类的值。