【发布时间】:2013-02-03 12:19:42
【问题描述】:
我有一个名为 Base 的基类,它定义了一个虚函数。 Derived 类现在继承自它并实现/覆盖该虚函数。以下代码可以正常工作:
Base* pB = new Derived();
pB->virtual_function(); // function of class Derived gets called -> good
我的问题是,我现在将所有派生实例存储在 STL 容器 std::map<ID, Base*> 中。这似乎会导致问题,因为当我稍后迭代该容器并尝试让每个 Base* 调用我的虚拟函数时,运行时仅将指针识别为类型 Base*并且不调用类中的重写实现Derived。
有没有办法让它按预期工作,或者我在这里错过了一个关键点?
编辑 1: 请求了一些额外的代码,所以我们开始吧:
std::map<ComponentType, Base*> m_Components;
// The factory instantiates a Derived* (via functors) and returns it as Base*
Base* pB = m_pComponentFactory->createComponent(this, type);
// Lazy insert (since there is no map entry with key 'type' at that stage)
m_Components[type] = pB;
[...]
Base* pB;
for(ComponentMap::const_iterator it = m_Components.begin(); it != m_Components.end( ); ++it)
{
pB = it->second;
pB->virtual_function(); // goes to Base instead of Derived
}
编辑 2: 我刚刚意识到的一件事是,在通过仿函数创建 Derived 实例后,我没有调用 dynamic_cast(或类似的东西)(但我不知道要转换什么无论如何,因为它都是通用/动态的)。它只是一个return creator(),创建者是函子。是这个问题吗?
创建者类型(函数类型)的定义:
typedef Base*(*ComponentCreator)([some params]);
编辑 3: 例如,实际的仿函数是这样定义的(Renderable 和 Location 是从 Base 派生的类):
&Renderable::Create<Renderable> // or
&Location::Create<Location>
Create() 方法是 Base 类中的模板函数。
template<typename T>
static Component* Create([some params])
{
return new T([some params]);
}
编辑 4: 问题似乎是我的 clone() + CopyConstructor 处理。我的克隆目前看起来像这样:
Base* Base::clone() const
{
return new Base(*this);
}
由于我只创建了一个Base*,所以后面的虚拟分辨率无法工作。不过,我现在剩下的问题是,我不知道如何更改克隆。如 EDIT 1 所示,我的 m_Components 映射带有 Base* 指针。我现在需要克隆它们,但我只知道它们是 Base* 的,而不是精确派生的。想到的一个想法可能是将用于创建 Derived 实例的函子首先存储在类中,以便以后重用。所以我的克隆看起来像这样:
Base* Component::clone() const
{
return m_pCreationFunctor([some params]);
}
有人看到更好的方法吗?
【问题讨论】:
-
你能展示你如何在容器中存储你的元素吗?理论上,你不应该有这个问题。
-
你做错了。这个想法是正确的,应该可行。你是不是不小心切到了任何地方?
-
到目前为止看起来还不错。函子是您可能进行切片的最明显的地方。您可以在这里发布正在使用的特定函子的定义吗?
-
既然到目前为止一切正常,试试这个:禁用基类中的复制构造和赋值以帮助排除切片。如果您的编译器支持它,请将覆盖添加到派生类的 virtual_function 声明以排除隐藏。
-
通常你只需将
clone()设为虚拟,并为每个类实现Base* Derived::clone() const { return new Derived(*this); }。
标签: c++ inheritance stl overriding virtual