缺省情况下 ,类的成员函数是非虚拟的 nonvirtual ,当一个成员函数为非虚拟的时候通过一个类对象(指针或引用)而被调用的该成员函数, 就是该类对象的静态类型中定义的成员函数 例如
void Query::display( Query *pb )
{
set<short> *ps = pb->solutions();
// ...
display();
}
pb 的静态类型是 Query* 非虚拟的 solutions()调用的是 Query 的成员函数 而非虚拟函数display()通过隐式 this 指针被调用 this 指针的静态类型也是 Query* 所以被调用的函数是 Query 的成员函数
要把对象声明为虚拟的 我们只需指定关键字 virtual
class Query {
public:
virtual ostream& print( ostream& = cout ) const;
// ...
};
当成员函数是虚拟的时候 通过一个类对象(指针或引用)而被调用的该成员函数 是在该类对象的动态类型中被定义的成员函数 。但是 ,正如所发生的, 一个类对象的静态和动态类型是相同的。
所以 虚拟函数机制只在使用指针和引用时才会如预期般地起作用,只有在通过基类指针或引用间接指向派生类子类型时, 多态性才会起作用 使用基类对象并不会保留派生类的类型身份 例如 考虑下列代码段
NameQuery nq( "lilacs" );
// ok: 但是 nq 被 "切割" 成一个 Query 子对象
Query qobject = nq;
用nq 初始化 qobject 是合法的: qobject 现在等于Query 基类子类型nq。 但是 ,qobject并不是一个 NameQuery 对象。 在初始化 qobject 之前 ,nq 的NameQuery 部分被切除。 在C++的面向对象程序设计中, 具有讽刺意味的是 ,我们必须使用指针以引用而不是对象来支持它(指面向对象程序设计 )例如 在下面的代码段中
void print( Query object,
const Query *pointer,
const Query &reference )
{
// 直到运行时刻才能确定
// 调用哪个 print() 实例
pointer->print();
reference.print();
// 总是调用 Query::print()
object.print();
}
int main()
{
NameQuery firebird( "firebird" );
print( firebird, &firebird, firebird );
}