我有三种不同的基类:
class BaseA
{
public:
virtual int foo() = 0;
};
class BaseB
{
public:
virtual int foo() { return 42; }
};
class BaseC
{
public:
int foo() { return 42; }
};
然后我从这个基础派生出来(用A代替X代替A,B或C):
class Child : public BaseX
{
public:
int foo() { return 42; }
};
如何在三个不同的基类中重写该函数?我的以下三个假设是否正确?还有其他警告吗?
答案 0 :(得分:16)
要记住的重要规则是,一旦函数声明为虚拟,派生类中具有匹配签名的函数始终是虚拟的。因此,对于A的Child和B的Child,它被覆盖,它的行为相同(除了你不能直接实例化BaseA)。
但是,使用C,函数不会被覆盖,而是会被重载。在那种情况下,只有静态类型很重要:它会调用它的指针(静态类型)而不是对象的真实类型(动态类型)
答案 1 :(得分:14)
在派生类中,如果在基类中将方法定义为virtual,则该方法是虚拟的,即使在派生类的方法中未使用关键字virtual。
BaseA
,它将按预期编译和执行,foo()
为虚拟并在类Child
中执行。BaseB
相同,它也将按预期编译和执行,foo()
为virtual()并在类Child
中执行。BaseC
,它将编译并执行,但如果您从BaseC
的上下文和BaseC
版本调用它,它将执行Child
版本如果您使用Child
。答案 2 :(得分:2)
使用BaseA,子类不会 编译,纯虚函数 未定义
只有在尝试创建BaseA对象时才会出现这种情况。如果您创建Child的对象,则可以使用BaseA *或Child *
调用foo()使用BaseB,孩子的功能 在BaseB *上调用foo时调用 或儿童*。
取决于对象的类型,因为对象可以是BaseB或Child。如果对象是BaseB,则调用BaseB :: foo。
使用BaseC,孩子的功能 在Child *上调用foo时调用 但不是BaseB *(函数在 父类被称为。)
是的,但你永远不想这样做。
答案 3 :(得分:2)
从多态性的角度来看,更喜欢A,所以你知道每个孩子都有自己的虚函数实现。
如果您具有有效的默认实现,则主要选择B,但是您必须确保所有子类都根据需要具有自己的实现。
C不是多态,所以要明智地使用。
答案 4 :(得分:1)
这主要取决于你如何称呼它。
如果你这样做:
class Child : public BaseA
{
public:
int foo() { return 42; }
};
并且做了
BaseA baseA = new Child();
baseA->foo();
它会调用Child的foo函数。
但是,如果你这样做了:
BaseA baseA = new BaseA();
会产生编译时错误。
答案 5 :(得分:0)
Class Child 将编译,您无法实例化该类型的对象。
如果您要从Base覆盖某些函数,然后再次派生,这可能很有用。