异质集合调用派生类函数 c++



我有类A,B,C。 B 和 C 派生自 A.B 有一个函数 foo()。 如果我创建一个 A* 数组并用 B*-s 和 C*-s 填充它,那么我就不能在 B* 元素上调用 foo(),因为编译器会在 A 中搜索它。 有没有办法做到这一点,或者 A 也必须包含一个 foo() 函数?

函数foo()只知道B对象。 这意味着你有一个指向A的指针,你不能确定对象是否有这样的功能。这就是为什么编译器会抱怨错误的原因。

问题的解决方案是多态性。

备选方案 1:在 A 中使函数成为虚拟函数

使用这种方法,您将拥有一个空的foo()函数,该函数对所有AC对象不执行任何操作,但您将在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(); 
}

这里是在线演示

对于记录,我使用了指针向量而不是数组。 但原理是一样的。

另请注意,经验法则是,如果你在一个类中有一个虚函数,你也应该有一个虚拟析构函数(为了简单起见,我在这里省略了它)。

备选方案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;
}

这里是在线演示

dynamic_cast是智能强制转换:如果指向的对象类型与目标类型不匹配,则dynamic_cast返回nullptr

备选方案3:不推荐

如果 A 不能是多态的,则可以考虑最后一种选择,但是如果您有知道 A* 的平均值来确定对象是否为 B。可能是这种情况,如果在 A 中您有一些关于对象类型的信息。在这种情况下,您可以考虑static_cast.

但是,不建议这样做:

  • 您必须管理自己一种了解对象类型的方法(因此您将手动管理,当类型是多态时编译器自动执行的操作)。
  • 如果你在static_cast中犯了一个错误,即你认为对象是B,但实际上不是,那么你就会有一个未定义的行为。