我有 A、B、C 类。 B 和 C 是从 A 派生的。B 有一个函数 foo()。 如果我创建一个 A* 数组并用 B*-s 和 C*-s 填充它,那么我无法在 B* 元素上调用 foo(),因为编译器将在 A 中搜索它。 有没有办法做到这一点,或者 A 也必须包含 foo() 函数?
最佳答案
函数 foo()
仅适用于 B
对象。这意味着您有一个指向A
的指针,您无法确定该对象是否具有这样的功能。这就是编译器会提示错误的原因。
解决您问题的方法是多态性。
替代方案 1:将 A 中的函数设为虚函数
通过这种方法,您将拥有一个空的 foo()
函数,该函数对所有 A
和 C
对象不执行任何操作,但是您会用 B
中的正确函数覆盖。
示例:
struct A {
virtual void foo () { cout<<"nothing!"<<endl; }
};
struct B : A {
void foo () override { cout<<"this is a B object: foo!"<<endl; }
};
struct C : A {};
int main() {
vector<A*> va;
va.push_back (new A);
va.push_back (new B);
va.push_back(new C);
for (auto x : va)
x->foo();
}
这里是online demo
根据记录,我使用了指针 vector 而不是数组。但原理是一样的。
还请注意,经验法则是,如果类中有虚函数,则也应该有虚析构函数(为了简单起见,我在此处省略了它)。
替代方案2:使类多态并使用dynamic_cast
通过这种方法,您只需为 B
对象定义 foo()
。诀窍是,当您迭代容器时,您会检查该对象是否是 B
(这要求该对象是多态的),如果是,则调用该函数。
示例:
struct A {
virtual ~A() {}; // to make A and its descendents polymorphic, you need at least one virtual function
};
struct B : A {
void foo () { cout<<"this is a B object: foo!"<<endl; }
};
struct C : A {};
int main() {
vector<A*> va;
va.push_back (new A);
va.push_back (new B);
va.push_back(new C);
for (auto x : va) {
auto maybe = dynamic_cast<B*>(x);
if (maybe) // yes, it's a B*
maybe->foo();
else cout << "still not a B"<<endl;
}
return 0;
}
这里是online demo
dynamic_cast
是一种智能强制转换:如果指向的对象类型与目标类型不匹配,则 dynamic_cast
返回 nullptr
.
替代方案 3:不推荐
如果 A 不能是多态的,但如果您有办法知道 A* 来确定该对象实际上是否是 B,则可以考虑最后一种选择。如果在 A 中您有一些有关对象类型的信息,则可能是这种情况。在这种情况下,您可以考虑使用 static_cast
。
但是不建议这样做:
- 您必须自己管理一种方法来了解对象的类型(因此您需要手动管理,当类型是多态时编译器会自动执行的操作)。
- 如果您在
static_cast
中犯了错误,即您认为该对象是 B 但实际上并非如此,那么您就会出现未定义的行为。
关于c++ - C++ 异构集合调用派生类函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43006122/