指向模板类的指针

时间:2014-06-23 23:20:15

标签: c++ templates pointers

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

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()是常见函数,并使用模板作为返回类型。所以我不明白如何使用基类。

有什么想法吗?

3 个答案:

答案 0 :(得分:5)

没有名为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,看看这是否足以解决您的问题。

答案 1 :(得分:1)

您可以指定如下类型:

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

或者Graph也是模板化的:

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

答案 2 :(得分:1)

首先,正如我所说,你需要一个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<Base>代替Vertex*

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

现在在run()指针上调用Vertex时,需要dynamic_cast指针返回相应的派生类。在您的情况下,由于run()是纯虚函数,因此无法在Vertex*上实际调用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();
};