没有前向声明,是否存在不完整嵌套类型的语法?

时间:2015-06-17 19:23:20

标签: c++ c++11 nested forward-declaration

以下程序产生诊断错误。

#include <memory>
class Containing {
    // class Nested;                 // [1]: This line seems required.
    typedef std::shared_ptr<class Nested> Ptr;
    class Nested {
        Ptr & ptr ();
        void foo (const Ptr &p) {
            p->ptr() = ptr()->ptr(); // [2]: Error here without [1]
        }
    };
};
int main () {}

产生的诊断是:

prog.cpp:8:14: error: invalid use of incomplete type 'class Nested'
             p->ptr() = ptr()->ptr();
              ^
prog.cpp:4:35: error: forward declaration of 'class Nested'`
     typedef std::shared_ptr<class Nested> Ptr;
                                   ^

但是,如果我取消注释前向声明,则编译成功。我相信原因是Nested在用于shared_ptr<>时不会嵌套。如果是这样,是否有一种语法可以让shared_ptr<>知道Nested是否嵌套而没有前向声明?类似的东西:

class Containing {
    typedef std::shared_ptr<class Containing::Nested> Ptr;
    //...

这个问题使用一个最小的例子来说明问题。实际结构如下:

class Containing {
    typedef std::shared_ptr<class NestedInterface> Ptr;
    class NestedObject {
        Ptr ptr_;
        //...
    };
    class NestedInterface {
        virtual NestedObject & object () = 0;
        void foo (const Ptr &p) {
            // ...
        }
        //...
    };
    class NestedType1 : NestedInterface {
        NestedObject obj_;
        NestedObject & object () { return obj_; }
        //...
    };
    class NestedType2 : NestedInterface {
        Containing &c_;
        NestedObject & object () { return c_.nested_object_; }
        //...
    };
    //...

2 个答案:

答案 0 :(得分:1)

你应该在那里保留声明class Nested;

声明PtrNested关系是一个鸡与蛋的问题,前向声明是解决这个问题的正确方法。

编译器需要知道令牌Nested是一个类,而不是其他东西。在编译器达到Ptr时,该信息就足够了,并且该类的详细信息尚不相关。然后编译器到达完整的Nested声明,详细信息可用于该类以后的所有用途。

答案 1 :(得分:1)

没有。

但是,您根本不需要避免前向声明。这有效:

class Containing {
    class NestedInterface;
    typedef std::shared_ptr<NestedInterface> Ptr;
    class NestedObject {
        Ptr ptr_;
        //...
    };
    class NestedInterface {
        // ...
    };
};

有时,类中的交叉依赖可能会使这很难做到。在这种情况下,您需要做的就是避免内联定义引用类,而是将其他类声明为异地,如下所示:

class Containing {
    class NestedInterface;
    class NestedObject;
    typedef std::shared_ptr<NestedInterface> Ptr;
};
class Containing::NestedObject {
    Ptr ptr_;
    //...
};
class Containing::NestedInterface {
};

请注意,通常,在C ++中,嵌套类不会像在其他语言中那样随意使用 - 通常可以与外部类实现相同的效果,并且它们的行为方式要好得多。 (它们不需要外部类的定义。)只有少数情况下它们是绝对必要的。 (std::allocator<T>::rebind<U>浮现在脑海中。)