【问题标题】:Why subclass method isn't called?为什么不调用子类方法?
【发布时间】:2023-03-05 16:37:01
【问题描述】:

我对子类化和使用方法有疑问。

我创建了一个B 类的实例并将其存储为指向A 的指针。但是当我使用指针调用重载方法时,输出是“A”而不是“B”。为什么?

这适用于其他语言,我做错了什么?

#include <iostream>
using namespace std;

class A {
public:
    void f() {
        cout << "A";
    }
};

class B : public A {
public:
    void f() {
        cout << "B";
    }
};

int main() {
    A *a = new B();
    a->f();
    return 0;
}

【问题讨论】:

  • 声明 A 的 f() 方法是虚拟的。用于在运行时推迟 binging。否则为
  • 是的,因为它不是虚拟的

标签: c++ class polymorphism


【解决方案1】:

f()需要在基类A中声明virtual

class A {
public:
    virtual void f() {
        cout << "A";
    }
};

您已经使用过的其他语言可能默认使用虚拟方法,但 C++ 不会(不要为您不使用的东西付费:虚拟方法在调用它们时会产生间接性,这意味着它们比正常方法稍慢方法调用)。

通过添加virtual,绑定将推迟到运行时(称为dynamic binding),而f() 函数调用将取决于值的类型

因为您没有将函数f() 声明为虚拟,所以绑定是静态的(在编译时)并将使用变量的类型(但不是值)来确定要调用哪个f() .因此,在您当前的代码语句中,a-&gt;f(); 调用了A 类的f(),因为a 是指向A 类的指针。

【讨论】:

    【解决方案2】:

    为了实现多态行为,基类的方法必须是virtual

    所以在class A 中,您需要将void f() 更改为virtual void f()

    【讨论】:

      【解决方案3】:

      函数必须声明为virtual 才能覆盖它:

      #include <iostream>
      using namespace std;
      
      class A {
      public:
          virtual void f() {// Here you must define the virtual.
              cout << "A";
          }
      };
      
      class B : public A {
      public:
          virtual void f() { //Here the "virtual" is optional, but a good practice
              cout << "B";
          }
      };
      
      int main() {
          A *a = new B();
          a->f();
          return 0;
      }
      

      【讨论】:

      • 当子类提供已经在基类中定义的方法的实现时,method overriding 不会重载。
      【解决方案4】:

      当你没有指向基类的指针时,你可能会遇到这个问题,但是它的实际实例(不适用于本问题中的示例)

      就我而言,我有一个类 Token 及其子类 Word

      class Token {
         public: virtual string toString() { ... }
      }
      class Word: public Token {
         public: string toString() { ... }
      }
      

      将它们存储在std::map&lt;string, Token&gt; 中并从中检索我希望在这样的代码中调用Word::toString()

      std::map<string, Token> words;
      words.insert("test", Word(...));
      words["test"].toString();
      

      我每次都打电话给Token::toString()

      解决方案: 使用像 std::map&lt;string, Token*&gt; 这样的指针并将所有实例视为指针 (TBH,我已经讨厌指针了)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-17
        • 2017-10-31
        • 2015-07-30
        • 1970-01-01
        • 2021-08-24
        • 2018-08-22
        • 2012-04-25
        • 1970-01-01
        相关资源
        最近更新 更多