我有子类化和使用方法的问题。
我创建了一个类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;
}
答案 0 :(得分:21)
f()
需要在基类A中声明virtual
:
class A {
public:
virtual void f() {
cout << "A";
}
};
您已经使用过的其他语言可能默认为虚方法,但C ++不支持(不支付您不使用的内容:虚拟方法在调用它们时会产生间接,这意味着它们比正常情况稍慢方法调用)。
通过添加virtual
,绑定将推迟到运行时(称为dynamic binding),并且将在类型的值上决定f()
函数调用。
因为你没有将函数f()
声明为虚拟,所以绑定是静态的(在编译时)并且将使用类型的变量(但不是值)来确定{{1}打电话。因此,在您目前的代码中,f()
调用a->f();
类的A
,因为f()
是指向a
类的指针。
答案 1 :(得分:6)
为了实现多态行为,基类的方法必须是virtual
。
因此,在class A
中,您需要将void f()
更改为virtual void f()
。
答案 2 :(得分: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;
}
答案 3 :(得分: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,我已经讨厌指针了)