我有三个不同的基类:

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 中的某些函数,然后再次派生,这可能会很有价值。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top