#include<iostream>
using namespace std;
enum note {middleC,Csharp,Cflat};
class Instrument{
public:
virtual void play(note) const{
cout<< "Instrument::play"<<endl;
}
virtual char*what() const{
return "Instrument";
}
virtual void adjust(int) {cout << "adjust(int) from Instrument!"<<endl;}
};
class Wind : public Instrument{
public:
void play(note) const{
cout << "Wind::play"<<endl;
}
char* what() const{
return "Wind";
}
void adjust(int) {cout << "adjust(int) from Wind!"<<endl;}
};
class Percussion : public Instrument{
public:
void play(note) const {
cout << "Percussion::play"<<endl;
}
char* what() const{
return "Percussion";
}
void adjust(int){}
};
class Stringed : public Instrument{
public:
void play(note) const{
cout<< "stringed::play"<<endl;
}
char* what() const {return "stringed";}
void adjust(int){}
};
class Brass : public Wind{
public:
void play(note) const{
cout<< "Brass::play"<< endl;
}
char* what() const {return "Brass";}
};
class Woodwind : public Wind{
public:
void play(note) const{
cout << "Woodwind::play" << endl;
}
char* what() const {return "Woodwind";}
};
void tune(Instrument& i){
i.play(middleC);
}
//New function:
void f(Instrument& i){
i.adjust(1);
}
//upcasting during array initialization:
Instrument *A[] = {
new Wind,
new Percussion,
new Stringed,
new Brass,
};
int main(){
Wind flute; //Wind:Instrument
Percussion drum;//Percussion:Instrument
Stringed violin;//Stringed:Instrument
Brass flugelhorn;//Brass:Wind
Woodwind recorder;//Woodwind:Wind
tune(flute);
tune(drum);
tune(violin);
tune(flugelhorn);
tune(recorder);
f(flugelhorn);
}
可以看到,这个例子已在Wind之下增加了另外的继承层,但不管这里有多少层, virtual机制仍会正确工作。针对Brass和Woodwind, adjust()函数没有重写(重新定 义)。当出现这种情况时,将会自动地调用继承层次中“最近”的定义—编译器保证对于虚 函数总是有某种定义,所以决不会出现最终调用不与函数体捆绑的情况(这种情况将导致 灾难)。 数组A[]存放指向基类Instrument的指针,所以在数组初始化过程中发生向上类型转 换。这个数组和函数f()将在稍后的讨论中用到。 在对tune()的调用中,向上类型转换在对象的每一个不同的类型上完成。总能得到 期望的结果。这可以被描述为“发送一条消息给一个对象,让这个对象考虑用它来做什 么”。virtual函数使我们在分析项目时可以初步确定:基类应当出现在哪里?应当如何扩 展这个程序?在程序最初创建时,即便我们没有发现合适的基类接口和虚函数,但在稍后 或者更晚,当决定扩展或维护这个程序时,也常常会发现它们。这不是分析或设计错误, 它只意味着一开始我们还没有所有的信息。由于C++中严格的模块化,因此这并不是大问 题。因为当我们对系统的一部分进行修改时,往往不会像C那样波及系统的其他部分。