我们在第14章的最后学习了对象指针,并且在编写链表类的过程中已经能熟练地使用它了。现在有了继承之后,我们的心中有了疑问:父类指针能否指向子类对象?子类指针能否指向父类对象?如果那样使用指针,对象的功能是否会受到限制呢?
我们修改程序17.3.1,用程序的运行结果来解答我们的疑问:
//student.h和undergraduate.h同程序17.3.1
//main.cpp
#include <iostream>
#include "undergraduate.h"
using namespace std;
int main()
{
Undergraduate s1;//新建一个本科生对象
Undergraduate *s1p;//新建一个子类的对象指针
student s2;
student *s2p;//新建一个父类的对象指针
s1p=&s2;//这行程序出错了
s2p=&s1;
s1.set("Tom",21,178,60);
cout <<s1.sname <<s1.sage <<endl;
s2p->set("Jon",22,185,68);
cout <<s1.sname <<s1.sage <<endl;
s1p->setGPA(2.5);
s2p->setGPA(3.0); //这行程序出错了
return 0;
}
编译结果:
main.cpp(10) : error C2440: '=' : cannot convert from 'class student *' to 'class Undergraduate *'
main.cpp(17) : error C2039: 'setGPA' : is not a member of 'student'
根据编译结果,我们可以看到,在公有继承情况下父类的对象指针指向子类对象是允许的。如s2p学生指针指向本科生s1,因为本科生也是学生;子类的对象指针指向父类是禁止的。如s1p本科生指针不能指向学生s2,因为学生不一定是本科生。
此外,如果我们用父类的对象指针指向子类对象,那么这个指针无法使用子类中扩展出的成员。如s2p指针无法设置本科生的绩点,因为使用了学生指针,本科生就变成了学生的身份,学生身份不再有设置绩点的功能。
我们再次修改程序17.3.1,使得它能够运行:(程序17.5)
//student.h和undergraduate.h同程序17.3.1
//main.cpp
#include <iostream>
#include "undergraduate.h"
using namespace std;
int main()
{
Undergraduate s1;
student s2;
student *s2p;
s2p=&s1;
s1.set("Tom",21,178,60);
cout <<s1.sname() <<'\t' <<s1.sage() <<endl;
s2p->set("Jon",22,185,68);
cout <<s1.sname() <<'\t' <<s1.sage() <<endl;
return 0;
}
运行结果:
Constructing a student without parameter...
Constructing a student without parameter...
Tom 21
Jon 22
现在程序能够正常运行了。可见,用s1设置本科生信息和用s2p指针设置学生信息都是可行的。
假设我们为学生类和本科生类都写了一个名为study的成员函数。两者的名称相同,参数表相同,实现却不相同。当子类和父类有着两个名字和参数表完全相同的函数时,我们把这个现象称为覆盖(Overlap)。如下面的代码:
//student.h
class student//学生类作为父类
{
public:
……
void study();
protected:
char name[10];
int age;
int height;
int weight;
};
……
void student::study()
{
cout <<"随便学些什么。" <<endl;
return;
}
//undergraduate.h
class Undergraduate:public student
{
public:
……
void study();
protected:
double GPA;//本科生绩点
};
……
void Undergraduate::study()
{
cout <<"学习高等数学和大学英语。" <<endl;
return;
}
如果有一个本科生对象s1和一个学生对象s2,那么显然s1.study()会是学习高等数学和大学英语,s2.study()会是随便学些什么。但是,如果有一个学生类的指针sp,它也能指向本科生对象,这时调用sp->study()会是怎么样的呢?我们发现,即使它指向一个本科生对象,它也只能“随便学些什么”。这样的结果在情理之中,却并不是我们期望的。我们希望程序能够“猜”到sp指针指向了哪种对象,并且调用各自的study成员函数。这个功能如何才能实现?在之后的几节我们会作讲解。