2012-02-11 100 views
3

我在下面有一个特定的场景。下面的代码应该打印B和C类的'say()'函数并打印'B说..'和'C说...'但它不会。任何想法..我正在学习多态,所以也有在下面的代码行中评论了与它相关的几个问题。多态对象列表

class A 
{ 
public: 
// A() {} 
    virtual void say() { std::cout << "Said IT ! " << std::endl; } 
    virtual ~A(); //why virtual destructor ? 
}; 

void methodCall() // does it matters if the inherited class from A is in this method 
{ 
    class B : public A{ 
    public: 
     // virtual ~B(); //significance of virtual destructor in 'child' class 
     virtual void say() { // does the overrided method also has to be have the keyword 'virtual' 
      cout << "B Sayssss.... " << endl; 
     } 
    }; 
    class C : public A { 
    public: 
     //virtual ~C(); 
     virtual void say() { cout << "C Says " << endl; } 
    }; 

    list<A> listOfAs; 
    list<A>::iterator it; 

    # 1st scenario 
    B bObj; 
    C cObj; 
    A *aB = &bObj; 
    A *aC = &cObj; 

    # 2nd scenario 
    // A aA; 
    // B *Ba = &aA; 
    // C *Ca = &aA; // I am declaring the objects as in 1st scenario but how about 2nd scenario, is this suppose to work too? 

    listOfAs.insert(it,*aB); 
    listOfAs.insert(it,*aC); 

    for (it=listOfAs.begin(); it!=listOfAs.end(); it++) 
    { 
     cout << *it.say() << endl; 
    } 
} 

int main() 
{ 
    methodCall(); 
    return 0; 
} 

回答

2

你的问题被称为切片,你应该检查这个问题:Learning C++: polymorphism and slicing

你应该声明此列表的指针的列表A S:

list<A*> listOfAs; 

,然后插入这些aBaC指向它的指针,而不是创建它们指向的对象的副本。你插入元素列表的方式是错的,你倒是应该使用push_back功能插入:

B bObj; 
C cObj; 
A *aB = &bObj; 
A *aC = &cObj; 

listOfAs.push_back(aB); 
listOfAs.push_back(aC); 

然后你的循环可能看起来像这样:

list<A*>::iterator it; 
for (it = listOfAs.begin(); it != listOfAs.end(); it++) 
{ 
    (*it)->say(); 
} 

输出:

B Sayssss.... 
C Says 

希望这可以帮助。

+0

其实*使用*一个裸指针的容器是一个潘多拉的黄蜂巢,但任何数量的东西都可能出错... – 2012-02-11 16:32:30

+0

我同意。但在这种情况下,我认为使用裸指针更合适,以便他更好地理解到底发生了什么。 – LihO 2012-02-11 16:36:08

+0

在上面的情况下,我不得不照顾列表中的元素,一旦我用它..我必须删除它或什么? – LivingThing 2012-02-15 18:52:16

1

多态性虚拟类层次的只能通过引用指针到基子:

struct Der : Base { /* ... */ }; 

Der x; 

Base & a = x; 

a.foo(); // calls Der::foo() from x 

功能foo是多态的调度,如果它是在Base一个虚函数;多态性是指这样一个事实,即当您调用Base类型的对象的成员函数时,实际调用的函数可以在类Der中实现。

容器只能存储固定类型的元素。为了存储一个多态的集合,你可以拥有一个指向基类的指针的容器。既然你需要存储的实际对象的其他地方,生命周期管理是不平凡的,最好的留给专用包装如unique_ptr

#include <list> 
#include <memory> 


int main() 
{ 
    std::list<std::unique_ptr<Base>> mylist; 

    mylist.emplace_back(new Der1); 
    mylist.emplace_back(new Der2); 
    // ... 

    for (p : mylist) { p->foo(); /* dispatched dynamically */ } 
} 
+0

1:这是什么“容器只能存储固定类型的元素”。意味着?? 2:“你可以改为容器指向基类” 你的意思是'列表 listOfAs'而不是'列表 listOfAs;' – LivingThing 2012-02-15 19:01:46

0

list::iterator it; B bObj; C cObj; A *aB = &bObj; A *aC = &cObj; listOfAs.insert(it,*aB);

你不需要初始化 “它”? 我相信你应该这样做= listOfAs.begin();在开始插入之前。