多態能夠方便我們編寫程序,可以讓不同的類與它獨特的成員函數一一對應。即使我們只是簡單地“稱呼”,程序也會很明白我們的心思。那么,多態應該如何實現呢?
多態的實現
在C++中,我們把表現多態的一系列成員函數設置為虛函數。虛函數可能在編譯階段并沒有被發現需要調用,但它還是整裝待發,隨時準備接受指針或引用的“召喚”。設置虛函數的方法為:在成員函數的聲明最前面加上保留字virtual。注意,不能把virtual加到成員函數的定義之前,否則會導致編譯錯誤。
下面我們把各種學生的學習都設置為虛函數,了解如何實現多態:(程序17.7.1)
//student.h
#include <iostream>
using namespace std;
class student
{
public:
student(char *n,int a,int h,int w);
student();
void set(char *n,int a,int h,int w);
char * sname();
int sage();
int sheight();
int sweight();
virtual void study();//把學習設置為虛函數
protected:
char name[10];
int age;
int height;
int weight;
};
char * student::sname()
{
return name;
}
int student::sage()
{
return age;
}
int student::sheight()
{
return height;
}
int student::sweight()
{
return weight;
}
void student::set(char *n,int a,int h,int w)
{
int i;
for (i=0;n[i]!='/0';i++)
{
name[i]=n[i];
}
name[i]='/0';
age=a;
height=h;
weight=w;
return;
}
student::student(char *n,int a,int h,int w)
{
cout <<"Constructing a student with parameter..." <<endl;
set(n,a,h,w);
}
student::student()
{
cout <<"Constructing a student without parameter..." <<endl;
}
void student::study()//成員函數定義處沒有virtual
{
cout <<"隨便學些什么。" <<endl;
return;
}
//undergraduate.h
#include "student.h"
class Undergraduate:public student
{
public:
double score();
void setGPA(double g);
bool isAdult();
virtual void study();//把學習設置為虛函數
protected:
double GPA;
};
double Undergraduate::score()
{
return GPA;
}
void Undergraduate::setGPA(double g)
{
GPA=g;
return;
}
bool Undergraduate::isAdult()
{
return age>=18?true:false;
}
void Undergraduate::study()//成員函數定義處沒有virtual
{
cout <<"學習高等數學和大學英語。" <<endl;
return;
}
//pupil.h
class Pupil:public student
{
public:
virtual void study();//把學習設置為虛函數
};
void Pupil::study()
{
cout <<"學習語數外。" <<endl;
return;
}
//main.cpp
#include <iostream>
#include "undergraduate.h"
#include "pupil.h"
using namespace std;
int main()
{
Undergraduate s1;
student s2;
Pupil s3;
student *sp=&s1;//sp指向本科生對象
s1.set("Tom",21,178,60);
sp->study();//體現多態性
sp=&s2; //sp指向學生對象
s2.set("Jon",22,185,68);
sp->study();//體現多態性
sp=&s3; //sp指向小學生對象
s3.set("Mike",8,148,45);
sp->study();//體現多態性
return 0;
}
運行結果:
Constructing a student without parameter...
Constructing a student without parameter...
Constructing a student without parameter...
學習高等數學和大學英語。
隨便學些什么。
學習語數外。
我們看到,將學習設置為虛函數之后,無論對象指針sp指向哪種學生對象,sp->study()的執行結果總是與對應的類相符合的。多態就通過虛函數實現了。
我們在編寫成員函數的時候,可以把盡可能多的成員函數設置為虛函數。這樣做可以充分表現多態性,并且也不會給程序帶來不良的副作用。
無法實現多態的虛函數
使用虛函數可以實現多態,但是如果在使用虛函數的同時再使用重載,就會可能使虛函數失效。我們修改程序17.7.1,看看重載會給虛函數帶來些什么麻煩:(程序17.7.2)
//student.h
#include <iostream>
using namespace std;
class student
{
public:
student(char *n,int a,int h,int w);
student();
void set(char *n,int a,int h,int w);
char * sname();
int sage();
int sheight();
int sweight();
virtual void study(int c=0);//設置為虛函數,帶默認參數
protected:
char name[10];//姓名
int age;//年齡
int height;//身高
int weight;//體重
};
……
void student::study(int c)
{
cout <<"隨便學些什么。" <<endl;
return;
}
//undergraduate.h和pupil.h同程序17.7.1
//main.cpp
#include <iostream>
#include "undergraduate.h"
#include "pupil.h"
using namespace std;
int main()
{
Undergraduate s1;
student s2;
Pupil s3;
student *sp=&s1;
s1.set("Tom",21,178,60);
sp->study(1);//帶參數
sp=&s2;
s2.set("Jon",22,185,68);
sp->study();
sp=&s3;
s3.set("Mike",8,148,45);
sp->study();
return 0;
}
運行結果:
Constructing a student without parameter...
Constructing a student without parameter...
Constructing a student without parameter...
隨便學些什么。
隨便學些什么。
隨便學些什么。
當學生類的study成員函數和本科生類的study成員函數參數格式不同時,即使把學生類中的study設置為虛函數,編譯器也無法找到本科生類中與之完全相同的study函數。多態是在程序員沒有指定調用父類還是某個子類的成員函數時,電腦根據程序員的要求,揣測并選擇最合適的成員函數去執行。但是當成員函數的參數格式不同時,程序員在調用成員函數的各種參數無疑就是在暗示到底調用哪個成員函數。這時電腦豈敢自作主張揣測人類的心思?因此,要使用虛函數實現多態性,至少要使各個函數的參數格式也完全相同。