11

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

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

4 回答 4

22

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

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

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

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

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

于 2013-02-18T15:10:28.153 回答
6

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

因此,class A您需要更改void f()virtual void f().

于 2013-02-18T15:09:29.817 回答
2

该函数必须声明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;
}
于 2013-02-18T15:20:36.300 回答
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,我已经讨厌指针了)

于 2020-10-19T21:33:35.400 回答