#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函数永远不会被调用。
顺便说一下,这是我在一个更大的对象中看到的问题的简化版本,我只是以这些对象为例。
答案 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()。