-
06-07-2019 - |
题
我有三个不同的基类:
class BaseA
{
public:
virtual int foo() = 0;
};
class BaseB
{
public:
virtual int foo() { return 42; }
};
class BaseC
{
public:
int foo() { return 42; }
};
然后我从这样的基础导出(用 X 代替 A、B 或 C):
class Child : public BaseX
{
public:
int foo() { return 42; }
};
三个不同基类中的函数是如何重写的?我的以下三个假设正确吗?还有其他注意事项吗?
- 对于 BaseA,子类无法编译,纯虚函数也未定义。
- 对于 BaseB,当在 BaseB* 或 Child* 上调用 foo 时,会调用子进程中的函数。
- 对于 BaseC,当在 Child* 上调用 foo 时,会调用子类中的函数,但不会在 BaseB* 上调用 foo(调用父类中的函数)。
解决方案
在派生类中,如果在基类中定义了 virtual 方法,则该方法是虚拟的,即使在派生类的方法中未使用关键字 virtual。
- 和
BaseA
, ,它将按预期编译和执行,其中foo()
虚拟并在课堂上执行Child
. - 与相同
BaseB
, ,它也会按预期编译和执行,foo()
是 virtual() 并在类中执行Child
. - 和
BaseC
但是,它会编译并执行,但它会执行BaseC
版本如果你从上下文中调用它BaseC
, ,以及Child
版本如果你调用上下文Child
.
其他提示
要记住的重要规则是,一旦函数被声明为虚函数,派生类中具有匹配签名的函数始终是虚函数。因此,它被 A 的 Child 和 B 的 Child 覆盖,其行为相同(除了不能直接实例化 BaseA)。
然而,对于 C,该函数不是被重写,而是重载。在这种情况下,只有静态类型很重要:它将根据指向的指针(静态类型)而不是对象的实际内容(动态类型)来调用它
使用Basea,儿童类未编译,纯虚拟函数未定义
仅当您尝试创建 BaseA 对象时才会出现这种情况。如果创建 Child 的对象,然后可以使用 BaseA* 或 Child* 调用 foo()
使用BaseB,在BaseB*或Child*上调用FOO时,调用了孩子的功能。
取决于对象的类型,因为对象可以是 BaseB 或 Child。如果对象是 BaseB,则调用 BaseB::foo。
使用BASEC,当调用孩子*但在baseb*上调用foo时,调用了孩子的功能(调用父类中的功能)。
是的,但你永远不想这样做。
从多态性的角度来看,更喜欢 A,所以你知道每个孩子都有自己的虚函数实现。
如果您有有效的默认实现,则主要选择 B,但是您必须确保所有子类都根据需要拥有自己的实现。C 不是多态性,因此请谨慎使用。
这主要取决于你如何称呼它。
如果你这样做:
class Child : public BaseA
{
public:
int foo() { return 42; }
};
并做了
BaseA baseA = new Child();
baseA->foo();
它将调用 Child 的 foo 函数。
但是,如果您这样做:
BaseA baseA = new BaseA();
它会产生编译时错误。
班级儿童 将要 如果从 A 派生,则编译,您只是无法实例化该类型的对象。
如果您要重写 Base 中的某些函数,然后再次派生,这可能会很有价值。