指向模板类的指针
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
模板参数的每个组合,但这听起来不太好。您可能需要检查您的设计,看看是否有其他方法可以解决您的问题。你想达到什么目的?您可以问另一个更针对此的问题。
如果Vertex
s 在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<Base>
而不是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<int, int>
另一个可能是Vertex<double, long>
等等
@subzero 你可以使用我的第二个建议。
但是在这种情况下,当我实例化一个 Graph 对象时,我将只使用一种 Vertex 对象。
不,你可以做Graph<double, long>
。
我的意思是,如果我实例化说Graph<int, int> x
。那我就不行了x.vertices['xyz'] = 1.12121
。以上是关于指向模板类的指针的主要内容,如果未能解决你的问题,请参考以下文章