void*指针的C++替代品(不是模板)

Vol*_*ire 7 c++ polymorphism templates pointers

看起来我对C++有一个基本的误解:<

我喜欢多态容器解决方案.谢谢你,因为我引起了我的注意:)


因此,我们需要创建一个相对通用的容器类型对象.它也恰好封装了一些与业务相关的逻辑.但是,我们需要在这个容器中存储基本上任意的数据 - 从原始数据类型到复杂类.

因此,人们会立即跳到模板类的想法并完成它.但是,我注意到C++多态性和模板不能很好地结合在一起.由于存在一些我们将要工作的复杂逻辑,我宁愿坚持使用模板或多态,而不是试图通过同时做两者来对抗C++.

最后,鉴于我想做一个或另一个,我更喜欢多态.我发现更容易表示像"这个容器包含可比类型"这样的约束 - 一个la java.

让我谈到问题的主题:最抽象的是,我想我可以拥有一个"容器"纯虚拟界面,它具有类似于"push(void*data)和pop(void*data)"的东西(用于记录) ,我实际上并没有尝试实现堆栈).

但是,我并不喜欢顶级的void*,更不用说每次我想要为具体容器可以使用的数据类型添加约束时签名都会改变.

总结:我们有相对复杂的容器,有各种方法来检索元素.我们希望能够改变可以进入容器的元素的约束.元素应该与多种容器一起使用(只要它们满足特定容器的约束).

编辑:我还应该提到容器本身需要是多态的.这是我不想使用模板化C++的主要原因.

那么 - 我应该放弃对Java类型接口的热爱并使用模板吗?我应该使用void*并静态地投射一切吗?或者我应该使用一个空类定义"元素"来声明什么,并将其用作"元素"层次结构中的顶级类?

我喜欢堆栈溢出的原因之一是许多响应提供了一些我甚至没有考虑过的其他方法的有趣见解.所以,请提前感谢您的见解和意见.

Gre*_*ers 14

如果要将真正的任意数据存储到容器中,可以使用boost :: any的标准容器.

这听起来更像是你想要像boost :: ptr_container这样的东西,其中任何可以存储在容器中的东西必须从某种基类型派生,而容器本身只能给你对基类型的引用.


Lev*_*Lev 5

如果正确使用多态性和模板,它们可以很好地协同工作.

无论如何,我知道你想在每个容器实例中只存储一种类型的对象.如果是这样,请使用模板.这将防止您错误地存储错误的对象类型.

至于容器界面:根据你的设计,也许你也可以让它们模板化,然后它们会有类似的方法void push(T* new_element).当您想要将对象添加到容器(未知类型)时,请考虑您对该对象的了解.这个对象首先来自哪里?一个返回的函数void*?你知道它会被比较吗?至少,如果你的代码中定义了所有存储的对象类,你可以使它们都从一个共同的祖先继承,比如说,而不是Storable使用.Storable*void*

现在,如果您看到对象将始终通过类似的方法添加到容器中void push(Storable* new_element),那么在将容器设置为模板时实际上没有任何附加值.但是你会知道它应该存储Storables.


Dim*_*ima 5

简单的事情是定义一个名为的抽象基类Container,并为您希望存储的每种项目创建子类.然后你可以使用任何标准的集合类(std::vector,std::list,等)来存储指针Container.请记住,既然你要存储指针,就必须处理它们的分配/释放.

但是,您需要一个集合来存储这种截然不同的类型的对象这一事实表明应用程序的设计可能存在问题.在实现此超级通用容器之前,最好重新检查业务逻辑.


Ecl*_*pse 4

是否可以没有包含元素的根 Container 类:

template <typename T>
class Container
{
public: 

   // You'll likely want to use shared_ptr<T> instead.
   virtual void push(T *element) = 0;
   virtual T *pop() = 0;
   virtual void InvokeSomeMethodOnAllItems() = 0;
};

template <typename T>
class List : public Container<T>
{
    iterator begin();
    iterator end();
public:
    virtual void push(T *element) {...}
    virtual T* pop() { ... }
    virtual void InvokeSomeMethodOnAllItems() 
    {
       for(iterator currItem = begin(); currItem != end(); ++currItem)
       {
           T* item = *currItem;
           item->SomeMethod();
       }
    }
};
Run Code Online (Sandbox Code Playgroud)

然后可以多态地传递这些容器:

class Item
{
public:
   virtual void SomeMethod() = 0;
};

class ConcreteItem
{
public:
    virtual void SomeMethod() 
    {
        // Do something
    }
};  

void AddItemToContainer(Container<Item> &container, Item *item)
{
   container.push(item);
}

...

List<Item> listInstance;
AddItemToContainer(listInstance, new ConcreteItem());
listInstance.InvokeSomeMethodOnAllItems();
Run Code Online (Sandbox Code Playgroud)

这以类型安全的通用方式为您提供了 Container 接口。

如果你想对可以包含的元素类型添加约束,你可以这样做:

class Item
{
public:
  virtual void SomeMethod() = 0;
  typedef int CanBeContainedInList;
};

template <typename T>
class List : public Container<T>
{
   typedef typename T::CanBeContainedInList ListGuard;
   // ... as before
};
Run Code Online (Sandbox Code Playgroud)