简体中文版翻译:申旻,nicrosoft@sunistudio.com
可以。有时(并非总是!)这是一个好主意。例如,假设所有Shape(图形)对象有一个公共的打印算法。但这个算法依赖于它们的面积并且它们都有不同的方法来计算面积。在这种情况下,Shape的area()方法(译注:得到Shape面积的成员函数)必须是virtual的(可能是纯虚(pure-virtual)的),但Shape::print()可以在Shape中被定义为非虚(non-virtual)的,前提是所有派生类不会需要不同的打印算法。
[ Top | Bottom | Previous section | Next section ]
是的,那是不同的策略。是的,那的确是使用虚函数的两种不同的基本方法:
强调一下,以上列表中的是“既/又”情况,而不是“二者选一”的。换句话说,在任何给定的类上,不必在两种策略中选择。既有一个符合策略 #1 的方法f(),又有一个符合策略 #2 的方法g()是非常正常的。换句话说,在同一个类中,有两种策略同时工作是非常正常的。
[ Top | Bottom | Previous section | Next section ]
当基类被构造时,对象还不是一个派生类的对象,所以如果 Base::Base()调用了虚函数
virt(),则 Base::virt() 将被调用,即使 Derived::virt()(译注:即派生类重写的虚函数)存在。
同样,当基类被析构时,对象已经不再是一个派生类对象了,所以如果 Base::~Base()调用了virt(),则 Base::virt()得到控制权,而不是重写的 Derived::virt()
。
当你可以想象到如果 Derived::virt() 涉及到派生类的某个成员对象将造成的灾难的时候,你很快就能看到这种方法的明智。详细来说,如果 Base::Base()调用了虚函数 virt(),这个规则使得 Base::virt()被调用。如果不按照这个规则,Derived::virt()将在派生对象的派生部分被构造之前被调用,此时属于派生对象的派生部分的某个成员对象还没有被构造,而 Derived::virt()却能够访问它。这将是灾难。
[ Top | Bottom | Previous section | Next section ]
合法但不合理。
有经验的 C++ 程序员有时会重新定义非虚函数(例如,派生类的实现可能可以更有效地利用派生类的资源),或者为了回避隐藏规则。即使非虚函数的指派基于指针/引用的静态类型而不是指针/引用所指对象的动态类型,但其客户可见性必须是一致的。
[ Top | Bottom | Previous section | Next section ]
意思是:你要完蛋了。
你所处的困境是:如果基类声明了一个成员函数f(int),并且派生类声明了一个成员函数 f(float)(名称相同,但参数类型和/或数量不同),那么 Base 的 f(int)被隐藏(hidden)而不是被重载(overloaded)或被重写(overridden)(即使 基类的f(int)是虚拟的)
以下是你如何摆脱困境:派生类必须有一个被隐藏成员函数的using 声明,例如:
如果你的编译器不支持using语法,那么就重新定义基类的被隐藏的成员函数,即使它们是非虚的。一般来说这种重定义只不过使用::语法调用了基类被隐藏的成员函数,如,
[ Top | Bottom | Previous section | Next section ]
如果你得到一个连接错误"Error: Unresolved or undefined symbols detected: virtual table for class Fred",那么可能是你在 Fred 类中有一个未定义的虚成员函数。
编译器通常会为含有虚函数的类创建一个称为“虚函数表”的不可思议的数据结构(这就是它如何处理动态绑定的)。通常你根本不必知道它。但如果你忘了为Fred 类定义一个虚函数,则有时会得到这个连接错误。
许多编译器将这个不可思议的“虚函数表”放进定义类的第一个非内联虚函数的编辑单元中。因此如果 Fred 类的第一个非内联虚函数是 wilma(),那么编译器会将 Fred 的虚函数表放在 Fred::wilma() 所在的编辑单元里。不幸的是如果你意外的忘了定义 Fred::wilma(),那么你会得到一个"Fred's virtual table is
undefined"(Fred的虚函数表未定义)的错误而不是“Fred::wilma() is undefined”(Fred::wilma()未定义)。
[ Top | Bottom | Previous section | Next section ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Apr 8, 2001