【问题标题】:Unable to define a class that is declared publicly in another class (and more problems)无法定义在另一个类中公开声明的类(以及更多问题)
【发布时间】:2015-01-06 04:00:32
【问题描述】:

我正在制作一个程序,其中一个两个类非常密切相关,所以我想在另一个里面声明一个,这样用户就必须使用 Class::member 语法来创建和派生这个类类型。我已经将我的程序抽象为 4 个类并重新创建了错误。课程是:

GraphInterface, Graph, GraphIteratorInterface, and GraphIterator.

Graph 从它的接口和迭代器公开派生的地方。现在因为迭代器只能与这些图一起使用,我希望用户必须通过去创建一个

Graph<int>::GraphIterator<int> it;

我试图通过在 GraphInterface 类中声明 GraphIteratorInterface 类,然后将其定义为单独的 .h 文件来实现这一点。然后我在 Graph 类(派生自 GraphInterface)中声明 GraphIterator,然后像往常一样在它自己的 cpp 文件中定义它。

代码在 ideone 上:http://ideone.com/3fByCl 当我尝试运行所有内容时,我得到了错误

"error: too few template-parameter-lists class GraphInterface<V>::GraphIteratorInterface {" 

在其他错误中。我不明白怎么会缺少模板参数,我肯定给了它一个(V)。

编辑 - 代码在这里

#include <iostream>
#include <vector>
using namespace std;

template<class V>
class GraphInterface {
    public:
    // Abstract GraphIterator class, defined elsewhere
    template<class VE> class GraphIteratorInterface;

    virtual ~GraphInterface();

    // BFS that uses the graph iterator class to perform work on the discovered
    // vertices and edges
    virtual void BFS(V src_vertex, GraphIteratorInterface<V> *) = 0;

};

template<class V>
class Graph : public GraphInterface<V> {
    public :
    template<class VE> class GraphIterator; // implements the graph-iter interface

    ~Graph();

    void BFS(V src_vertex, GraphIterator<V> *);
};

template<class V>
class GraphInterface<V>::GraphIteratorInterface {

    virtual void examine_edge(/*Edge Object*/) = 0;
    virtual void discover_vertex(const V &) = 0;
    // ...
};

template<class V>
class Graph<V>::GraphIterator : public GraphInterface<V>::GraphIteratorInterface {
    std::vector<V> vertices;
    //.. other members not in the interface
    void examine_edge(/*Edge Object*/);
    void discover_vertex(const V &)
};

int main() {
    Graph<int> g;
    return 0;
}

【问题讨论】:

  • 代码应该嵌入问题而不是链接。
  • 我马上改,谢谢指点。我认为你们可以编译它并自己查看错误这一事实会有所帮助。

标签: c++ class oop templates


【解决方案1】:

首先,您可能根本不需要GraphIteratorInterfaceGraphIterator 作为模板。也就是从

开始
template<class V>
class GraphInterface {
public:
    class GraphIteratorInterface;

然后从这里继续。

以下内容仅涉及成员模板的语言方面。你不需要在你的真实代码中使用这些。

  1. 如果你定义类模板的成员模板,语法是这样的:

    template<class V> 
    template<class VE>
    class GraphInterface<V>::GraphIteratorInterface { ...
    

是的,连续使用两次template&lt;class XYZ&gt;

  1. 当你使用类模板的成员模板时,你必须使用这个语法:

    template<class V> 
    template <class VE>
    class Graph<V>::GraphIterator 
      : public GraphInterface<V>::template GraphIteratorInterface<VE> {
    

也就是说,在成员模板名称前使用::template 而不是::

带有这些修复的代码是here。由于与模板无关的另一个问题,它仍然无法编译。

本质上你有

interface XI
 member interface YI
 virtual f(YI)

class XC : XI
 class YC : XI::YI
 virtual f(YC)

你不能像这样覆盖一个虚函数。不同的参数列表意味着它是不同的函数。参数密切相关,但没关系。 YI和YC是两种不同的类型。

您必须重新设计您的界面,以免发生这种情况。 XC::f 必须使用与 XI::f 相同的签名。

您可能想让 YI 成为 XI 的模板参数,而不是成员。那就是:

template<class V, class Iter>
class GraphInterface {
  public:
    virtual void BSF(V, Iter*) = 0;

  template <class V> 
  class IterImpl { ...

  template <class V>
  class GraphImpl : public GraphInterface <V, IterImpl> { ...

您不能以这种方式在 GraphImpl 中定义 IterImpl。

【讨论】:

  • 感谢您的帮助!这些模板的东西在语法上有点难以理解。两个不同的签名会导致两个单独的函数是有道理的,但我认为由于 Iterator is a IteratorInterface,在参数列表中用一个替换另一个是有效的。
  • 不用担心,即使是经验丰富的专业人士也会经常犯这种错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多