- 函数重写(override)
函数重写是指在派生类中重新对基类中的虚函数重新实现,即函数名和参数都一样,只是函数的实现体不一样。函数重写主要实现了基类和派生类之间的多态性。
在C++中,只能同指针或者引用实现多态,不能通过普通的对象来实现多态。(以下就是用指针来实现多态)
#include<iostream>
using namespace std;
class Parent
{
public:
Parent() {};
virtual void play() //定义虚函数,
{
cout << "play alone" << endl;
}
void work() //此处不是虚函数
{
cout << "work alone" << endl;
}
};
class Child :public Parent
{
public:
Child() {};
void play() //继承类重写基类的虚函数
{
cout << "play together" << endl;
}
void work() //继承类覆盖了基类的函数,由于不是虚函数,所以不存在继承后重写的说法
{
cout << "work together" << endl;
}
void childhood()//继承类特有的函数
{
cout << "having fun" << endl;
}
};
int main()
{
Parent *pa = new Child();//定义一个指向基类的指针,并且指向了子类对象
pa->play(); //运行时多态的体现
pa->work();//这里调用的还是基类的函数,所以不是多态
//pa->childhood(); 编译出错,基类的指针不能调用基类没有的函数
return 0;
}
首先,在基类定义了一个虚函数work()函数,既然是虚函数,那么在子类里可以重写这个函数(注意是重写!重写!重写!不是覆盖也不是重载)。子类的Child中重写了work()函数,其他先忽略。然后在main()函数中定义了一个基类的指针parent,但是用该指针指向的是子类的对象,即new了一个Child对象。总之一句话就是定义一个积累的指针,用它指向子类对象,然后用积累的这个指针去调用work()函数,此时发生运行时的多态。从结果可以得出,定义基类指针,并指向子类对象,此时用基类指针去调用一个特殊的函数,即在基类中该函数为虚函数,而子类重写了这个虚函数,此时调用的这个函数在运行期间动态地绑定到了指针实际所指的对象,即子类对象,从而去调用子类的这个函数。
其次,在上述例子中,在main()函数中,指针pa还调用了play()函数,但是结果显示的是基类的play()函数的结果,为什么呢?因为play()函数在基类定义时不是虚函数,所以不存在多态这一特性。虽然基类和子类都有这个play()函数,但是子类仅仅是覆盖或者说是隐藏了基类的play()函数,并不是重写。而pa指针是基类指针,所以必定要去调用基类的play()函数。
最后,在Child类中,还有一个childhood()函数,该函数是子类特有的,与基类没有关系,所以用基类的指针pa调用这个函数时会出错,因为基类根本访问不到这个函数。这也是多态性的一个缺陷,即基类的指针只能访问到子类中重写了基类的哪些虚函数,而不能访问子类新增的特有的函数。
纯虚函数实现多态性的例子:
// 纯虚函数和继承关系体现运行期多态
#include <iostream>
// 父类因为包含纯虚函数,所以该类是抽象类,即不能定义对象
class parent
{
public:
parent() {}
// 父类的纯虚函数
virtual void eat() = 0;
};
class child : public parent
{
public:
child () {}
// 子类重写了父类的纯虚函数
void eat()
{
std::cout << "Child eat." << std::endl;
}
};
int main()
{
// parent pa0; // 编译期会出错,因为抽象类不能定义对象
// 注意抽象类虽然不能定义对象,但是可以定义指针用来指向具体类
parent* pa = new child();
pa->eat(); // 运行期多态的体现!!!
return 0;
}
//运行结果
Child eat.
由上可得:纯虚函数就是在虚函数后加了“=0”,而且在基类中没有任何实现,那么包含纯虚函数的类自然就被称为抽象类,抽象类是不能定义对象的,所以在main()函数中的第一行会报错,而在继承基类的子类中必须实现抽象类中的纯虚函数,否则也会出错。那有人就有疑惑了,抽象类不能定义对象,为什么main()函数中Parent *pa没有出错呢,这是因为抽象类虽然不能定义对象,但是可以定义指针,用来指向具体类,从而实现多态,一定要分清楚C++中的指针、引用和对象三者的关系,不能一概而论。