如何进行内部类的前置声明?

209

我有一个类,就像这样...

class Container {
public:
    class Iterator {
        ...
    };

    ...
};

在其他地方,我想通过引用传递Container::Iterator,但我不想包含头文件。如果我试图前向声明该类,我会得到编译错误。

在其他地方,我想通过引用传递Container::Iterator,但不希望包含头文件。如果尝试前向声明该类,则会导致编译错误。

class Container::Iterator;

class Foo {
    void Read(Container::Iterator& it);
};

编译上述代码会得到...

test.h:3: error: ‘Iterator’ in class ‘Container’ does not name a type
test.h:5: error: variable or field ‘Foo’ declared void
test.h:5: error: incomplete type ‘Container’ used in nested name specifier
test.h:5: error: ‘it’ was not declared in this scope

我如何进行前置声明这个类,以便我无需包含声明迭代器类的头文件?

3个回答

183

这是不可能的。你无法在容器外部前向声明嵌套结构体,只能在容器内部进行前向声明。

你需要执行以下操作之一:

  • 使类非嵌套
  • 更改声明顺序,使嵌套类完全定义
  • 创建一个共同的基类,既可以在函数中使用,也可以由嵌套的类实现。

2
常见的基类是我使用最多的解决方案。 - Coyote
9
这是错误的:http://en.cppreference.com/w/cpp/language/nested_types - Nikerboker
13
他们的意思是嵌套类不能在容器外部进行前向声明。链接中的示例是在容器定义内部前向声明嵌套类,这是一种不同的情况。 - Antonio Barreto
7
在C++中无法在容器外部前向声明嵌套结构似乎是一种限制,本应该是可行的。对吗?这不可能有什么原因吧? - HelloGoodbye
1
@Wolf 你说得有道理。通过在前向声明表达式中包含修饰符,不是可以指定吗?例如 class Container::(public Iterator) 或类似的方式?(我不是在谈论语言今天的设计,而是关于它理论上如何设计。) - HelloGoodbye
显示剩余6条评论

30

我认为在不完整的类上前向声明内部类是行不通的(因为没有类定义,无法知道是否实际存在内部类)。所以你需要包含Container的定义,并前向声明内部类:

class Container {
public:
    class Iterator;
};

然后,在另一个头文件中,实现 Container::Iterator:

class Container::Iterator {
};

那就只包含容器头文件(或者不用担心前向声明,直接包含两个头文件)


30
很好的回答,除了第一段括号中的那部分。"无法知道是否实际存在内部类"在这个上下文中没有意义,并且可能不准确。前向声明的整个目的是告诉编译器有一个类(或在这种情况下,一个内部类)。你的那个具体说法对于普通类也同样适用,这意味着你不能前向声明任何东西。 - Loduwijk

3

我不知道有没有办法完全满足你的需求,但是如果你愿意使用模板,这里有一个解决方法:

// Foo.h  
struct Foo
{
   export template<class T> void Read(T it);
};

// Foo.cpp
#include "Foo.h"
#include "Container.h"
/*
struct Container
{
    struct Inner { };
};
*/
export template<> 
  void Foo::Read<Container::Inner>(Container::Inner& it)
{

}

#include "Foo.h"
int main()
{
  Foo f;
  Container::Inner i;
  f.Read(i);  // ok
  f.Read(3);  // error
}

希望这个成语对你有所帮助(希望你的编译器是基于EDG并实现了export功能;)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接