Heterogen集合调用派生类函数c ++

时间:2017-03-24 17:52:29

标签: c++ polymorphism

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

1 个答案:

答案 0 :(得分:2)

函数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(); 
 }

这里是online demo

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

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

备选方案2:使类具有多态性并使用dynamic_cast

使用此方法,您只能为foo()对象定义B。诀窍是当您遍历容器时,检查对象是否为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,但实际上并非如此,那么您将有一个未定义的行为。