【问题标题】:C++ function overridingC++ 函数重写
【发布时间】:2009-06-22 23:46:09
【问题描述】:

我有三个不同的基类:

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(父类中的函数被调用)时,子类中的函数会被调用。

【问题讨论】:

    标签: c++ function polymorphism overriding


    【解决方案1】:

    要记住的重要规则是,一旦函数被声明为虚拟,派生类中具有匹配签名的函数始终是虚拟的。因此,它被 A 的 Child 和 B 的 Child 覆盖,它们的行为相同(除了不能直接实例化 BaseA)。

    然而,在 C 语言中,函数并没有被覆盖,而是被重载。在这种情况下,只有静态类型很重要:它会根据指向的指针(静态类型)而不是对象的真正含义(动态类型)调用它

    【讨论】:

      【解决方案2】:

      在派生类中,如果在基类中定义了虚拟方法,则该方法是虚拟的,即使在派生类的方法中没有使用关键字 virtual。

      • 使用BaseA,它将按预期编译和执行,foo() 是虚拟的并在类Child 中执行。
      • BaseB 相同,它也将按预期编译和执行,foo() 是 virtual() 并在类 Child 中执行。
      • 然而,使用BaseC,它将编译和执行,但如果你从BaseC的上下文中调用它,它将执行BaseC版本,如果你使用@的上下文调用它,它将执行Child版本987654331@.

      【讨论】:

        【解决方案3】:

        使用 BaseA,子类不会 编译,纯虚函数 没有定义

        仅当您尝试创建 BaseA 的对象时才适用。如果您创建一个 Child 对象,然后您可以使用 BaseA* 或 Child* 调用 foo()

        使用BaseB,子函数 在 BaseB* 上调用 foo 时调用 或孩子*。

        取决于对象的类型,因为对象可以是 BaseB 或 Child。如果对象是 BaseB,则调用 BaseB::foo。

        使用 BaseC,子函数 在 Child* 上调用 foo 时调用 但不在 BaseB* 上(函数在 父类被调用)。

        是的,但你永远不想这样做。

        【讨论】:

        • 我不想这样做有什么具体原因吗?相反,虽然我无法提出一个我想要这样做的例子。是有技术原因还是只是被认为是“不好的做法”?
        • 我没有看到任何技术原因..但这确实令人困惑。
        • @mizipzor 也许你继承了其他一些类,但你没有他们的代码。不是一个理想的设计,但它可能会发生。
        【解决方案4】:

        从多态的角度来看,更喜欢 A,所以你知道每个孩子都有自己的虚函数实现。
        如果您有一个有效的默认实现,主要选择 B,但是您必须确保所有子类都根据需要有自己的实现。 C 不是多态,请谨慎使用。

        【讨论】:

          【解决方案5】:

          这主要取决于你如何称呼它。

          如果你这样做了:

          class Child : public BaseA
          {
          public:
              int foo() { return 42; }
          };
          

          做了

          BaseA baseA = new Child();
          baseA->foo();
          

          它会调用 Child 的 foo 函数。

          但是,如果您这样做:

          BaseA baseA = new BaseA();
          

          这会产生编译时错误。

          【讨论】:

            【解决方案6】:
            如果从 A 派生

            Class Child 编译,您只是不能实例化该类型的对象。

            如果您要覆盖 Base 中的某些函数,然后再次派生,这可能会很有价值。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-07-03
              • 2013-06-10
              • 2014-11-21
              • 1970-01-01
              • 2016-01-21
              • 2015-03-24
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多