C++ 使用(n个空)基类在同一容器中存储不同的对象

C++ 使用(n个空)基类在同一容器中存储不同的对象,c++,containers,C++,Containers,假设我有两个完全不同的对象,Sprite和physicdata 我编写了一个空基类和一个容器类,可以将对象推送到容器或从容器中移除对象 我创建了其中两个容器来存储两个不同的对象——Sprite和physicdata。 不同的对象不在同一个类中 class base { }; class ContainerManager { public: std::vector<base*> list; void Push(base *object); void Remov

假设我有两个完全不同的对象,Sprite和physicdata

我编写了一个空基类和一个容器类,可以将对象推送到容器或从容器中移除对象

我创建了其中两个容器来存储两个不同的对象——Sprite和physicdata。 不同的对象不在同一个类中

class base
{
};

class ContainerManager
{
public:
    std::vector<base*> list;
    void Push(base *object);
    void Remove(base *object);
};

class PhysicsData : public base
{
    void applyGravity();
};

class Sprite : public base
{
    void Draw();
};

ContainerManager SpriteContainer;
ContainerManager PhysicsDataContainer;

Sprite aSprite;
SpriteContainer.Push(&aSprite);

PhysicsData SomeData;
PhysicsDataContainer.Push(&SomeData);
这是应该这样做的吗 要知道,在使用std::namespace前缀时调用的STL实际上是标准模板库:。很多模板类已经存在,例如,对于推/删除操作,请参见std::list

您可以这样使用它:

std::list<Sprite> SpriteContainer;
std::list<PhysicsData> PhysicsDataContainer;
等等

是C++模板的一个很酷的指南,如果你仍然想为更多的功能做你自己的类。 对于STD::列表,我不认为我需要解释STD::向量,如果你想做的事情,你就可以用向量。

< P>这不是C++的方式。你应该使用模板

要知道,在使用std::namespace前缀时调用的STL实际上是标准模板库:。很多模板类已经存在,例如,对于推/删除操作,请参见std::list

您可以这样使用它:

std::list<Sprite> SpriteContainer;
std::list<PhysicsData> PhysicsDataContainer;
等等

是C++模板的一个很酷的指南,如果你仍然想为更多的功能做你自己的类。


对于STD::清单,我不认为我需要解释STD::向量C++的用法,如果问题是你想做的事情。

你在C++中有模板,仍然担心有一个普通的基类来处理一个普通的容器??
template <class T>
class Container{
  private:
    vector<T> list;
  public:
    void Push(T data);
    T Pop();
};

C++中有模板,仍然担心有一个普通容器的普通基类??

template <class T>
class Container{
  private:
    vector<T> list;
  public:
    void Push(T data);
    T Pop();
};

如果将单个虚拟函数放入基类中,那么如果在同一容器中混合使用不同的类型,则可以使用dynamic_cast返回正确的指针。虚拟析构函数是一个好主意,因为如果对象是动态分配的,那么您可以删除该对象,而不必将其强制转换回原始指针


如果您不打算在单个容器中混合类型,我认为模板类会更好。这就是所有标准容器的实现方式。

如果将单个虚拟函数放入基类中,那么如果在同一容器中混合使用不同类型,则可以使用dynamic_cast返回正确的指针。虚拟析构函数是一个好主意,因为如果对象是动态分配的,那么您可以删除该对象,而不必将其强制转换回原始指针


如果您不打算在单个容器中混合类型,我认为模板类会更好。这就是所有标准容器的实现方式。

这看起来像是技术上正确的代码,但您没有进行任何类型检查。如您所见,PhysicData显示在您的SpriteContainer中。你可能不想要这个

有多种方法可以将PhysicasData从SpriteContainer中删除。一种方法是使用模板。使用模板,您可以说明容器在编译时应使用的基本对象的类型

另一种方法是从ContainerManager继承两种类型的ContainerManager,一种称为PhysicContainerManager,另一种称为SpriteContainerManager。这两个子类可以执行类型检查,以验证所传递的对象实际上是SpriteContainer或PhisicsData。这个链接显示了如何在C++

中进行类型检查 谢谢
jose

这看起来像是技术上正确的代码,但您没有进行任何类型检查。如您所见,PhysicData显示在您的SpriteContainer中。你可能不想要这个

有多种方法可以将PhysicasData从SpriteContainer中删除。一种方法是使用模板。使用模板,您可以说明容器在编译时应使用的基本对象的类型

另一种方法是从ContainerManager继承两种类型的ContainerManager,一种称为PhysicContainerManager,另一种称为SpriteContainerManager。这两个子类可以执行类型检查,以验证所传递的对象实际上是SpriteContainer或PhisicsData。这个链接显示了如何在C++

中进行类型检查 谢谢
jose

它是否会给您带来任何错误或什么?不要只使用pre作为代码。把它放在前面4个空间,我才刚开始用C++,好奇。我不明白。您可以定义一个公共基础,以便可以在同一容器中挤压不同的对象。但你要做两个容器,分别存放。有什么好处?为什么不使用两个不同类型的容器呢?一个std::vector拥有相同的接口,不管它是什么类型的
,那么ContainerManager为您带来了什么?它是否会给您带来任何错误或什么?不要只对代码使用pre。把它放在前面4个空间,我才刚开始用C++,好奇。我不明白。您可以定义一个公共基础,以便可以在同一容器中挤压不同的对象。但你要做两个容器,分别存放。有什么好处?为什么不只是有两个不同类型的容器呢?一个std::vector无论它拥有什么类型都有相同的接口,那么ContainerManager为您带来了什么呢?该类的函数还处理其他事情,例如在传递给它的对象中调用函数。我明白了,那么您仍然需要使用模板。只需按照链接仔细阅读指南即可。在C++中,这不是最微不足道的事情。@安得烈,模板也是可能的。在您的例子中,当键入模板化类时,可以将模板看作是一个带有占位符的类型T,而类型T是未知的;但是您仍然可以调用未知类型T的函数,比如T::foo。只要确保在实例化具体类时这些函数确实存在。比如说ContainerManager,调用的函数(这里是foo)必须存在于Sprite中。该类的函数还处理其他事情,比如在传递给它的对象中调用函数。我明白了,那么你仍然需要使用模板。只需按照链接仔细阅读指南即可。在C++中,这不是最微不足道的事情。@安得烈,模板也是可能的。在您的例子中,当键入模板化类时,可以将模板看作是一个带有占位符的类型T,而类型T是未知的;但是您仍然可以调用未知类型T的函数,比如T::foo。只要确保在实例化具体类时这些函数确实存在。比如说ContainerManager,调用的函数(这里是foo)必须存在于Sprite中。SomeData实际上并不打算进入SpriteContainer。我的错。谢谢你指出这一点!SomeData实际上并不打算进入SpriteContainer。我的错。谢谢你指出这一点!C++中的POP函数一般不应该返回它移除的值,因为如果它确实如此,那么它就不可能在T的复制构造函数可以抛出的情况下提供强异常保证。也就是说,对于C++ 11,任何复制构造函数都可以抛出的类型应该有一个NoFun-Funt构造函数,所以只要你只使用最近编写的和良好行为类型的,问题就消失了。C++中的POP函数一般不应该返回它移除的值,因为如果它这样做了,那么它就不可能在T的复制构造函数可以抛出的情况下提供强异常保证。这就是说,对于C++11,任何复制构造函数可以抛出的类型都应该有一个nothrow move构造函数,因此只要您只使用最近编写的、性能良好的类型,这个问题就不会出现了。