为什么不调用子类方法?

Why subclass method isn't called?

本文关键字:类方法 调用 为什么不      更新时间:2023-10-16

我在子类化和使用方法方面有问题。

我创建了一个类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;
}

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

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

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

通过添加virtual,绑定将推迟到运行时(称为动态绑定),并且哪个f()函数调用将取决于值的类型

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

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

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

函数必须声明为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;
}

当没有指向基类的指针,而是指向基类的实际实例时,您可能会面临此问题(不适用于本问题中的示例)

在我的例子中,我有一个类Token及其子类Word:

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

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

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

相反,我每次都给Token::toString()打电话。

解决方案:使用类似std::map<string, Token*>的指针,并将所有实例视为指针(TBH,我已经讨厌指针了)