【问题标题】:C++ : Vector of template classC++:模板类的向量
【发布时间】:2013-04-19 02:36:54
【问题描述】:

我有一个名为 Cell 的模板类如下:-

template<class T>class Cell
{
    string header, T data;
}

现在我想要另一个名为 Row 的类。 Row 将有一个名为 Cells 的向量,这样我就可以将 Cell 和 Cell 类型的元素添加到该向量中。有可能吗?

如果是这样,我该怎么做? 提前致谢。

【问题讨论】:

  • 你想在一个向量中保存一行,例如一个 Cell、一个 Cell 和任何其他单元格类型?
  • 是的,你是对的。我正是想要那个。
  • 这是否意味着您想要多态容器?您只能使用动态多态性(继承)而不能使用静态多态性(模板)。
  • “我有一个名为 Cell 的模板类” 不,你没有。那是一个类模板,也就是说,它不是一个类。 Cell&lt;int&gt; 是一个类。 Cell&lt;float&gt; 也是一个类,Cell&lt;Cell&lt;std::vector&lt;double&gt;&gt;&gt; 也是。但它们是三个不同的、独立的类,没有任何共同之处。
  • 向量的所有元素必须属于同一类型,因此您不能将Cell&lt;float&gt;Cell&lt;int&gt; 放在一起。你需要使用指针和继承,而且你必须知道你在做什么。创建一个包含所有子类的无法使用的基类太容易了,然后您就无法访问它。您需要将肉放在基类中。这意味着它必须有一个不依赖于 T 的可用接口。

标签: c++ generics vector


【解决方案1】:

这样的?

template<class T>
class Row
{
private:
   std::vector<Cell<T> > cells;
};

好的,这个答案不正确。

所以,如果你想在一个vector 不同的单元格中存储 - 你应该使用一些动态类型标识(你可以使用一个基类并将指向它的指针存储在向量中,它只使用被覆盖的虚函数在所有派生类中,您可以存储boost::any 之类的内容并为每个插入的元素保存一些type-identification,以便将它们转换为真实类型并使用它)。

【讨论】:

  • Jakir - 注意最后一个 &gt; 之前的空格,以避免与 &gt;&gt; 运算符混淆。不过 C++11 不需要这个。
  • 它可能不起作用。因为在创建 Row 类型对象时,我必须提供类型参数。并且向量将属于该类型。
  • @JakirHossain 然后你可以再添加一个模板参数。并将其用于特定于行的事物,并将 T 用于单元格。
  • @JakirHossain 你不能在不使用一些基类或其他东西的情况下推入一个不同类型的向量,这样你就可以知道每个元素的确切类型。
  • @JakirHossain - 我想详细说明您要解决的问题:vector 是一个数组,因此其中的所有元素都应该具有相同的静态类型,但是 Cell 和 Cell 是不相关的类型(与 jave 中的泛型类不同)。
【解决方案2】:

另一个答案很好,但你可能想要:

template<class T>
class Row
{
private:
    class Cell {
        string header;
        T data;
    }

    std::vector<Cell> cells;
    ...
}

【讨论】:

    【解决方案3】:

    由于您提供的额外细节,前两个答案将不起作用。您需要的是一种称为单元变体的类型,然后您可以拥有这些类型的向量。例如:-

    enum CellType
    {
      Int,
      Float,
      // etc
    };
    
    class Cell
    {
      CellType type;
      union
      {
        int i;
        float f;
        // etc
      };
    };
    
    class Vector
    {
      vector <Cell> cells;
    };
    

    然而,添加新类型很麻烦,因为它需要大量代码来维护。另一种方法可以使用带有通用基类的单元格模板:-

    class ICell
    {
      // list of cell methods
    };
    
    template <class T>
    class Cell : public ICell
    {
      T data;
      // implementation of cell methods
    };
    
    class Vector
    {
      vector <ICell *> cells;
    };
    

    这可能会更好,因为您最初更新的代码较少以添加新的单元格类型,但您必须在单元格向量中使用指针类型。如果您按值存储单元格,vector &lt;ICell&gt;,那么您将因object slicing 而丢失数据。

    【讨论】:

    • +1。 union 不仅仅是痛苦,它也不是类型安全的,这是模板的全部目的。
    • 非常感谢。我将使用第二种方法。感谢所有试图帮助我的人。
    • 还有一件事,你能提供示例代码来添加元素和使用迭代器访问元素吗?提前致谢。
    • @JakirHossain:为了保持单一职责的原则,多问一些问题(插入向量、迭代等)而不是扩展这个问题。
    • Icell 不能用于访问封装的数据。而且你不能在基类中定义一个虚函数来提供对数据的访问,因为那时你会将'typename T'向上移动到类层次结构中,你将再次面临同样的问题,即定义 vector>细胞;这是不允许的。因此我认为这不是正确的答案
    【解决方案4】:

    这在 C++ 中不可能,而在 Java/Python 中可能是因为:在 C++ 向量中,STL 容器的存储(由 vector::data() 返回)包含所有对象实例按顺序打包。其中每个元素必须具有相同的大小。这使得寻址快速方便。因此,假设你定义了一个模板类A,

    template <class T>
    class A{
      int id;
      T obj;
    };
    

    它的大小取决于模板变量“T obj”。推送不同模板类型 T 的同一个类 A 会使向量中的每个元素具有不同的大小,因此,这是不可能的。唯一的方法是使用基类的 shared_ptr 或 unique_ptr 的向量。 C++11 和 Boost 都支持 shared_ptr 和 unique_ptr。每个派生类元素可以有不同的模板类型。这样,当基类指针的析构函数被调用时,派生类的析构函数就会被调用。例如,

    #include <memory>
    #include <vector>
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class A{};
    
    template <class T>
    class AImpl : public A{
    public:
        T obj;
        AImpl(T _obj):obj(_obj){}
        ~AImpl(){
            cout << "Deleting " << obj << endl;
        }
    };
    
    int main(int argc, char** argv)
    {
        AImpl <string>* a1 = new AImpl <string> ("string1234");
        AImpl <int>* a2 = new AImpl <int> (1234);
        AImpl <double>* a3 = new AImpl <double> (1.234);
        vector <shared_ptr<A>> As;
        As.push_back(shared_ptr<A>(a1));
        As.push_back(shared_ptr<A>(a2));
        As.push_back(shared_ptr<A>(a3));
    }
    

    记得使用 -std=c++11 编译以启用 C++11。

    输出:

    Deleting string1234
    Deleting 1234
    Deleting 1.234
    

    你得到你想要的! :)

    在 Java/Python 中,每个类对象变量实际上都是一个指针,因此,A 的 Java 数组或 A 的 Python 列表等价于 A 的指针的 C++ 数组。因此,您将获得基本相同的功能无需显式创建 shared_ptrs。

    【讨论】:

    • 您的程序将错误显示为cpp:25:13: error: 'shared_ptr' was not declared in this scope
    • @PraveenVinny 那是因为您没有使用 -std=c++11 进行编译。 shared_ptr 在 中仅适用于 C++11。
    猜你喜欢
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多