虚函数问题

时间:2010-01-15 20:18:51

标签: c++ inheritance polymorphism virtual

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>

class Helper 
{
public:
    Helper() { init(); }
    virtual void print() {
        int nSize = m_vItems.size();
        std::cout << "Size : " << nSize << std::endl;
        std::cout << "Items: " << std::endl;
        for(int i=0; i<nSize; i++) {
            std::cout << m_vItems[i] << std::endl;
        }
    }
protected:
    virtual void init() { m_vItems.push_back("A"); }
    std::vector<std::string> m_vItems;
};

class ItemsHelper : public Helper
{
public:
    ItemsHelper() { }
protected:
    virtual void init() { 
        Helper::init();
        m_vItems.push_back("B");
    }
};

int _tmain(int argc, _TCHAR* argv[]) {
    ItemsHelper h;
    h.print();
}

这个输出是向量的大小是1.我期望大小为2,因为在ItemsHelper :: init函数中我调用了基类Helper::init()函数,然后我向向量添加了第二个项目。问题是,不会调用ItemsHelper :: init,而是调用基类init函数。

我希望调用ItemsHelper :: init函数,我可以通过调用ItemsHelper ctor中的init函数而不是基类来实现。 但是,问题是,有没有更好的方法来实现它并仍然保持对基类中的init()的调用?因为如果我想创建一个Helper对象而不是ItemsHelper,那么init函数永远不会被调用。

顺便说一下,这是我在一个更大的对象中看到的问题的简化版本,我只是以这些对象为例。

4 个答案:

答案 0 :(得分:7)

在基类构造函数中,尚未构造派生类,因此派生类上的overriden函数尚不可用。这个地方有一个FAQ条目......我找不到。

最简单的解决方案是将.push_back("A") init部分放入Helper构造函数,将.push_back("B")部分放入ItemsHelper构造函数。这似乎就是你要做的事情,并削减了不必要的init虚函数。

答案 1 :(得分:4)

请注意虚拟函数在构造函数中不能像预期的那样工作!

Helper() { init(); }

在这里,init()将始终调用当前类(Helper)的“init”,即使它被标记为虚拟。

编辑: SO上有一个similar question

答案 2 :(得分:3)

一般情况下(除非你完全理解指定构造函数和虚函数是如何工作的),你不应该在构造函数中调用虚函数,因为你通常不会得到函数的“最虚拟”版本。虚函数在构造函数中如何工作的快速版本是,当调用虚函数时,您将获得当前正在构造的类层次的“当前”级别的函数。

有关详细信息,请参阅以下文章:

答案 3 :(得分:2)

问题在于虚函数不像您在构造函数中那样工作。构造ItemsHelper时,首先构造基类Helper。在它的构造函数中,对象的类型是Helper,因此对init的调用调用Helper :: init()。然后调用ItemsHelper构造函数。无法从基类构造函数调用派生类函数。你可以做的最好的事情是在构造ItemsHelper对象之后调用init()。