外部类中包含内部类的实例,而嵌套类定义在外部类之外。

5

C++

如果外部类至少有一个内部类实例作为数据成员,我该如何在外部类定义之外放置内部(嵌套)类的定义?我进行了搜索,但我找到的最相关的SO答案 (在源文件中定义嵌套类),没有一个例子涉及外部类具有内部对象作为数据成员。就声明而不是定义内部类而言,我遵循了那个答案,但我的代码仍然无法正常工作:

struct Outer
{
    struct Inner;
    Inner myinner;
    Outer() : myinner(2) {}
};

struct Outer::Inner
{
    Inner(int n) : num(n) {}
    int num;
};

int main()
{
    Outer myouter;
}

在VC11中,它会出现错误error C2079: 'Outer::myinner' uses undefined struct 'Outer::Inner'

为什么破碎的代码没有与InnerOuter的定义内部定义的版本等效的影响,就像以下工作代码一样?

struct Outer
{
    struct Inner
    {
        Inner(int n) : num(n) {}
        int num;
    } myinner;
    Outer() : myinner(2) {}
};
1个回答

6

这是一个红色的标志,但是您可以使用虚假模板来完成它。

template< typename = void >
struct Outer_temp
{
    struct Inner;
    Inner myinner;
    Outer_temp() : myinner(2) {}
};

typedef Outer_temp<> Outer; // Hide template from user.

template< typename v >
struct Outer_temp< v >::Inner
{
    Inner(int n) : num(n) {}
    int num;
};

int main()
{
    Outer myouter;
}

Inner在模板中是一个依赖类型,因此在定义实例、成员或任何其他上下文中不需要完整声明。只有在实例化发生时(在这种情况下是从main中)需要完整声明。

我无法想象出一个好的理由来做到这一点,但事实就是如此。

嵌套类不应该仅仅为了程序组织而使用。嵌套暗示着概念上的依赖性,“只有在外部提供的上下文中才能存在内部”。尽管通常会将容器节点类嵌套在容器中,但这可能会引起问题。SCARY习语是一种否定这种组织结构并获得改进的通用性的设计风格。

简而言之:独立地定义两个类,并使用嵌套的typedef将它们链接起来。


+1 如果有工作代码。我了解你的模板语法。但我不知道为什么它可以在你的假模板中工作,但在我的非模板中无法工作。我不能说我是一个模板专家。通过“内部模板中有一个依赖类型,因此当你定义一个实例时,在成员或任何其他上下文中,它不需要完全完成。只有在实例化发生时它才需要被完成。” 你的意思是我的 Inner 是独立的类型,并且在它被实例化为 Outer 内部时是不完整的吗? - CodeBricks
@CodeBricks中,“dependent”指的是依赖于模板参数。 “什么是inner?这取决于这是什么特化。” 模板可以使用在其后声明的类型进行实例化,因为模板允许引用不完整的类型,只要它们依赖于参数即可。 我引入了这样一个虚假的依赖关系,以推迟对“Inner myinner”的编译,直到“main”。 - Potatoswatter
为什么我的代码中 Inner 的声明不能推迟到 Outer 看到 InnerOuter 下面的定义之后再进行编译?这似乎在常规函数中是可行的。例如:void g(); void f(){g();} void(g){cout<<"hi\n";} - CodeBricks
1
@CodeBricks 可以仅使用声明而不需要定义就调用函数。在类被定义之前,无法实例化它。如果你在 Outer 中使用了 Inner *myinner,那么问题将永远不会发生,因为定义指针并不需要定义内部类。但是,指针运算 ++myinner 需要定义。规则太多啦 :P - Potatoswatter
在你的回答中,“独立定义这两个类并使用嵌套的typedef将它们链接起来”是什么意思?你是指这样做:struct Outer { /*...*/ typedef Inner itd; /*...*/}; struct Inner {/*...*/};吗?如果是这样,那么为什么要这样做?如果你想让InnerOuter之外不存在,那么这如何帮助InnerOuter之外更或者更少地被访问?无论哪个类将其实例用作数据成员,对Inner成员的可访问性不都取决于Inner的访问修饰符吗?或者你并没有想在那里放置“嵌套”这个词吗?你只是在引用你上面的代码吗? - CodeBricks
@CodeBricks 这是我的观点:类的嵌套并没有实现接口的可见性,它应该在实现方面反映概念上的可能性。你可以做出一些妥协,让用户拥有一个可以命名但不能实例化的类,使用“friend”。 - Potatoswatter

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