1.派生类可以重定义(“override(覆盖)”)基类的非虚函数吗?合法不合理。有时这样做是为了更好的利用派生类的资源,即使非虚函数的指派基于指针/引用的静态类型而不是指针/引用所指对象的动态类型,但其对客户可见性必须是一致的。
2.“
Warning: Derived::f(float) hides Base::f(int)” 意味着什么?
class Base {
public:
void f(double x); ← doesn't matter whether or not this is virtual
};
class Derived : public Base {
public:
void f(char c); ← doesn't matter whether or not this is virtual
};
int main()
{
Derived* d = new Derived();
Base* b = d;
b->f(65.3); ← okay: passes 65.3 to f(double x)
d->f(65.3); ← bizarre: converts 65.3 to a char ('A' if ASCII) and passes it to f(char c); does NOT call f(double x)!!
delete d;
return 0;
} 这个警告时说派生类f(float)函数和基类的
f(int)同名,派生类的函数隐藏了基类的函数,注意这不是重载(overloaded)或重写(overridden)
解决方法:使用using声明,例如:
class Base {
public:
void f(int);
};
class Derived : public Base {
public:
using Base::f; // This un-hides Base::f(int)
void f(double);
};
如果不支持Using,就使用重新定义基类的被隐藏的成员函数,使用::语法调用了基类被隐藏的成员函数
class Derived : public Base {
public:
void f(double x) { Base::f(x); } ← The redefinition merely calls Base::f(double x)
void f(char c);
};
注意:着这不是标准的一部分,所以不是编译器不一定会出现这个警告。
3.出现连接错误"virtual table" is an unresolved external”,意味着类中有一个未定义的虚成员方法。
许多编译器将“虚表”放进定义类的第一个非内联虚函数的编辑单元中。因此如果 Fred 类的第一个非内联虚函数是 wilma(),
那么编译器会将 Fred 的虚函数表放在 Fred::wilma() 所在的编辑单元里。不幸的是如果你意外的忘了定义 Fred::wilma(),
那么你会得到一个"Fred's virtual table is undefined"(Fred的虚函数表未定义)的错误而不是“Fred::wilma() is undefined”(Fred::wilma()未定义)。
4.如何设置使类使用不了继承:
简单的方法是将类的构造声明为私有或使用命名的构造函数(the Named Constructor Idiom),后者可以返回指针如果你想分配对象在堆上(使用new)或返回一个值如果你想分配对象在栈上。
加上注释也是很很行的方法,例如:// We'll fire you if you inherit from this class or even just /*final*/ class Whatever {...};
最后是使用虚继承,它可以使派生类的构造直接调用虚基类的构造。例如:下面的代码可以保证不能从Fred派生类。
class Fred;
class FredBase {
private:
friend class Fred;
FredBase() { }
};
class Fred : private virtual FredBase {
public:
...
}; 如果内存受限制,则要定义一个指针的内存到sizeof(Fred),这是因为大多数的编译器在实现虚继承时增加了一个指向派生类的指针。不过这因编译器而定。