简体   繁体   English

带有基类指针的虚函数+ STL容器

[英]Virtual function + STL container with base class pointers

I have a base class called Base which defines a virtual function. 我有一个称为Base的基类,它定义了一个虚函数。 The class Derived now inherits from it and implements/overwrites that virtual function. 现在, 派生类继承自它,并实现/覆盖该虚函数。 The following code works just fine: 以下代码可以正常工作:

Base* pB = new Derived();
pB->virtual_function(); // function of class Derived gets called -> good

My problem is, that I now store all my derived instances in a STL container std::map<ID, Base*> . 我的问题是,我现在将所有派生实例存储在STL容器std::map<ID, Base*> This seems to cause problems, because when I later iterate over that container and try for each Base * to call my virtual function, the runtime only recognizes the pointers as type Base * and does not call the overridden implementation in the class Derived . 这似乎引起了问题,因为当我以后遍历该容器并尝试让每个Base *调用我的虚函数时,运行时仅将指针识别为Base *类型,而不在Derived类中调用重写的实现。

Is there a way to get that working as intended or am I missing a crucial point here? 有没有办法使它按预期工作,还是我在这里错过了关键要点?

EDIT 1: Some additional code was requested, so here we go: 编辑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
}

EDIT 2: One thing I just realized is that I do not call dynamic_cast (or something similar) after creating the Derived instance via the functor (but I wouldn't know what to cast it to anyway since it is all generic/dynamic). 编辑2:我刚刚意识到的一件事是,在通过仿函数创建Derived实例后,我不调用dynamic_cast (或类似的东西)(但是我不知道将其强制转换为什么,因为它都是通用/动态的)。 It is just a return creator() with creator being the functor. 它只是一个return creator()并且creator是函子。 Is that the issue? 那是问题吗?

Definition of creator type (the functon type): 创建者类型(函子类型)的定义:

typedef Base*(*ComponentCreator)([some params]);

Edit 3: The actual functor is for example defined like this (Renderable and Location being derived classes from Base): 编辑3:例如,实际的仿函数定义如下(Renderable和Location是从Base派生的类):

&Renderable::Create<Renderable> // or
&Location::Create<Location>

with the Create() method being a template function in the class Base. Create()方法是Base类中的模板函数。

template<typename T> 
static Component* Create([some params]) 
{ 
    return new T([some params]); 
}

EDIT 4: The problems seems to be my clone() + CopyConstructor handling. 编辑4:问题似乎是我的clone()+ CopyConstructor处理。 My clone currently looks like this: 我的克隆当前看起来像这样:

Base* Base::clone() const
{
    return new Base(*this);
}

Since I only create a Base *, the virtual resolution later on cannot work. 由于我仅创建Base *,因此以后的虚拟分辨率无法正常工作。 The problem I am now left with though, is that I a missing an idea how to change the cloning. 我现在剩下的问题是,我缺少一个如何更改克隆的想法。 As shown in EDIT 1 I have my m_Components map with Base* pointers. 编辑1所示,我的m_Components映射具有Base *指针。 I now need to clone them but I only know that they are of Base * and not of which exact derivative. 我现在需要克隆它们,但我只知道它们是Base *,而不是确切的派生类。 One idea that comes to mind, might be to store functor used to create the Derived instance in the first place in the class, to reuse it later. 想到的一个想法可能是,将用于创建Derived实例的函子存储在类的首位,然后再使用。 So my clone would look something like this: 所以我的克隆看起来像这样:

Base* Component::clone() const
{
    return m_pCreationFunctor([some params]);
}

Anyone seeing a better approach? 有人看到更好的方法吗?

You are a victim of slicing. 您是切片的受害者。 When you copy construct a Base, you will lose the Derived parts of the object. 复制构造基本对象时,将丢失对象的“派生”部分。 See http://en.wikipedia.org/wiki/Object_slicing for a bit more detail. 有关更多详细信息,请参见http://en.wikipedia.org/wiki/Object_slicing If the base class is not supposed to be instantiated, you might consider making it abstract to prevent making this mistake in future. 如果不应该实例化基类,则可以考虑使其抽象化,以防止将来发生此错误。

The fix in this case is probably to have a virtual Base * clone() method and override it in derived classes. 在这种情况下,解决方法可能是使用虚拟的Base * clone()方法并在派生类中重写它。

ie

class Base{
...
virtual Base * clone() const = 0;
...
};

class Derived : public Base {
...
Base * clone() const override { return new Derived(*this); }
...
};

If you really want to avoid rewriting the clone method, you could use an intermediate CRTP class ie 如果您真的想避免重写clone方法,则可以使用中间CRTP类,即

struct Base{
    virtual Base * clone() = 0;
};

template <typename D>
struct B : public Base {
    virtual Base * clone() { return new D(*static_cast<D*>(this)); }
};

struct D : public B<D>{};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM