指向模板类的指针

Posted

技术标签:

【中文标题】指向模板类的指针【英文标题】:Pointers to templated class 【发布时间】:2014-06-23 23:20:14 【问题描述】:

我正在尝试定义一个图形,其中顶点类是使用模板定义的。然后我如何在另一个类中定义一个指向这个模板化顶点的指针。

template<class T1, class T2>
class Vertex 
public:
  virtual T1 run(T2) = 0;
;


class Graph 
  std::map<std::string, Vertex*> vertices; // <--- How do I do something like this
  int** adjacency_matrix;
public:
  void run() 
     ...
  
;

我一直在查看有关 Stack-Overflow 的其他一些问题,常见的建议似乎是使用未模板化的基类,并为此使用指针并将常用函数放入该类中。 但是,在我的代码中,函数run() 是常用函数,它使用模板作为返回类型。所以我不明白如何使用基类。

有什么想法吗?

【问题讨论】:

如果函数Vertex::run 使用模板参数,并且你想在没有模板参数的情况下存储指向Vertex 的指针,你将如何调用Vertex::run?你要传递给它什么? 这就是我遇到的问题。你有什么建议可以解决这个问题吗?。 C++ 是静态类型的,所以它需要在编译时知道类型。这意味着如果您要调用run(T2),它需要知道T2 是什么。您可以在Graph 中声明多个映射,每个映射用于您使用的Vertex 模板参数的每个组合,但这听起来不太好。您可能需要检查您的设计,看看是否有其他方法可以解决您的问题。你想达到什么目的?您可以问另一个更针对此的问题。 如果Vertexs 在Graph 中不知道他们的类型,您打算如何与他们互动? 【参考方案1】:

没有名为Vertex 的类,只有类的模板。

简单的出路是使用多态性,因为无论如何你只存储指针:

定义一个基类,所有Vertex 实例(特化或非特化)都继承自。

template<class T1, class T2>
class Vertex : VertexBase 
public:
  virtual T1 run(T2) = 0;
;

struct VertexBase 
  ~VertexBase() = default;
  template<class T1, class T2> T1 run(T2 x) 
    return dynamic_cast<Vertex<T1,T2>&>(*this).run(x);
  
;

不管怎样,也看看std::function,看看它是否能很好地解决你的问题。

【讨论】:

基类的问题是我需要使用run() 函数,并且使用模板。如何在基类中定义它? 添加了一个示例,使用基类中的模板调用run【参考方案2】:

首先,正如我所说,您需要一个非模板基类,Vertex 从中继承:

struct Base

    virtual ~Base() = default;
;

template<class T1, class T2>
class Vertex : public Base

public:
    virtual T1 run(T2) = 0;
;

然后在Graph 函数中使用std::shared_ptr&lt;Base&gt; 而不是Vertex*

class Graph 
    std::map<std::string, std::shared_ptr<Base>> vertices;
public:
    void run();
;

现在当在Vertex 指针上调用run() 时,您需要将dynamic_cast 指针返回到适当的派生类。在您的情况下,您实际上不能在 Vertex* 上调用 run(),因为 Vertex::run() 是一个纯虚函数。

int main()

    Graph g;
    g.vertices["xyz"] = std::make_shared<Vertex<int, int>>();
    // error: field type 'Vertex<int, int>' is an abstract class

如果你想调用Vertex,要么让run()成为一个非纯虚函数并给它一个实现,或者使用一个派生类来实现:

class Derived : public Vertex<int, int>

public:
    int run(int n)  std::cout << n << '\n'; return 0; 
;

class Graph 
    std::map<std::string, std::shared_ptr<Base>> vertices;
public:
    template<class T2>
    void call_run(std::shared_ptr<Base> p, T2 value)
    
        if (auto derived = std::dynamic_pointer_cast<Derived>(p))
            derived->run(value);

        if (/* other derived classes... */);
    

    void run();
;

【讨论】:

【参考方案3】:

您可以像这样指定类型:

std::map<std::string, Vertex<int, int>*> vertices;

或者也将Graph 模板化:

template<class T1, class T2>
class Graph 
    std::map<std::string, Vertex<T1, T2>*> vertices;

【讨论】:

问题是地图可以有Vertex类的不同模板实现。例如一个条目可能是Vertex&lt;int, int&gt; 另一个可能是Vertex&lt;double, long&gt; 等等 @subzero 你可以使用我的第二个建议。 但是在这种情况下,当我实例化一个 Graph 对象时,我将只使用一种 Vertex 对象。 不,你可以做Graph&lt;double, long&gt; 我的意思是,如果我实例化说Graph&lt;int, int&gt; x。那我就不行了x.vertices['xyz'] = 1.12121

以上是关于指向模板类的指针的主要内容,如果未能解决你的问题,请参考以下文章

包含指向派生模板类的基类指针的类的赋值运算符和复制构造函数

模板化函数或带有指向基类的指针的函数

模板类的智能指针?

基类的函数指针指向子类的成员函数?

通过指向base,static_cast,crtp,删除模板的指针派生的成员

指向模板类成员函数的函数指针