公有继承中的多态是指同一种方法在派生类和基类中具有不同的行为,具体的说,是指方法的行为取决于调用该方法的对象。多态,即具有多种形态,就是指同一个方法的行为随上下文而异。要实现多态公有继承,需要用到两种机制。
- 在派生类中重新定义基类的方法。
- 使用虚函数。
将《派生类和基类之间的关系》文章中的基类和派生类增加一个函数,用于计算各科成绩的平均分,基类对象有三科成绩,而派生类对象有五科成绩,这种情况下,同一方法在基类和派生类中的定义不同,可以用虚函数来实现基类和派生类中求各科成绩的平均分。基类和派生类的声明如下:
cpp
class Student
{
public:
...
unsigned short get_yuwen_score() { return yuwen_score; }
unsigned short get_shuxue_score() { return shuxue_score; }
unsigned short get_yingyu_score() { return yingyu_score; }
string get_name() { return name; }
virtual unsigned short GetMean();
virtual void show_score()
{
cout << "语文分数:" << yuwen_score << endl;
cout << "数学分数:" << shuxue_score << endl;
cout << "英语分数:" << yingyu_score << endl;
}
virtual ~Student() {}
private:
std::string name;
unsigned short yuwen_score;
unsigned short shuxue_score;
unsigned short yingyu_score;
};
class CulturalStudent :public Student
{
private:
unsigned short lishi_score;
unsigned short zhengzhi_score;
public:
...
virtual void show_score()
{
cout << "姓名:" << get_name() << endl;
Student::show_score();
cout << "历史分数:" << lishi_score << endl;
cout << "政治分数:" << zhengzhi_score << endl;
}
virtual unsigned short GetMean();
};
说明:基类中声明GetMean函数时使用了关键字virtual,此时,GetMean,show_score函数被称为虚函数。
将会在派生类中重新定义的基类中的函数声明为虚函数,在基类中被声明为虚函数后,它在派生类中将自动成为虚函数。不过,一般在派生类的声明中使用关键字virtual来指出哪些函数是虚函数。
虚函数的定义如下:
cpp
unsigned short Student::GetMean()
{
return (yuwen_score + shuxue_score + yingyu_score) / 3;
}
unsigned short CulturalStudent::GetMean()
{
return (get_shuxue_score() + get_yingyu_score() + get_yuwen_score() + zhengzhi_score + lishi_score) / 5;
}
说明:虚函数的实现不需要加关键字virtual,virtual关键字只用于类声明中的函数原型。
在程序中调用虚函数:
cpp
int main()
{
using namespace std;
CulturalStudent st1("xiaoming", 82, 99, 84, 90, 91);
Student st5("xiaohong", 90, 89, 78);
cout << st1.GetMean() << endl;///调用派生类中的GetMean函数
cout << st5.GetMean() << endl;///调用基类中的GetMean函数
Student *st2 = &st1;
Student *st3 = &st5;
st2->get_shuxue_score();///调用基类中的get_shuxue_score方法
st3->get_shuxue_score();///调用基类中的get_shuxue_score方法
cout<<st2->GetMean()<<endl;///调用派生类中的GetMean方法
cout<<st3->GetMean()<<endl;///调用基类中的GetMean方法
return 0;
}
程序说明:
- 基类和派生类中都声明了GetMean函数,此时,程序将根据对象类型来确定使用哪个版本。
如果要在派生类中重新定义基类的方法,则应将基类方法声明为虚拟的。这样,程序将根据对象类型而不是引用或指针的类型来选择方法版本。
- 如果方法是通过引用或指针调用的,如果函数没有使用virtual,程序将根据引用或指针类型确定调用的方法;如果函数使用了virtual,表明该函数在基类和派生类中都有定义,则程序将根据引用或指针指向的对象的类型来确定调用的方法。
3. 基类中声明了一个虚析构函数。在基类中定义虚函数后,通常将析构函数也设置成虚函数,以确保释放派生类对象时按正确的顺序调用析构函数。
- 派生类中的show_score函数展示了在派生类函数中调用基类函数的方式。
cpp
virtual void show_score()
{
cout << "姓名:" << get_name() << endl;
Student::show_score();
cout << "历史分数:" << lishi_score << endl;
cout << "政治分数:" << zhengzhi_score << endl;
}
派生类中的show_score函数显示新增的两个科目成绩,并调用基类中的show_score函数显示基类数据成员中的语数外三科成绩。在派生类方法中,必须使用作用域解析操作符来调用基类的虚函数, 该示例中如果没有使用作用域解析操作符,show_score函数将调用自身形成递归,导致无限循环**。**
示例中,get_name函数是基类中的函数,它不是虚函数,没有在派生类中重新定义,因此不需要使用作用域解析操作符。