嵌套类 - 将声明与C ++中的定义分开

时间:2014-06-08 22:13:08

标签: c++ nested-class

是否可以将类声明与其定义分开?当然是,但是如果我想在它的实际定义之前拥有这个类的对象呢?请考虑以下示例:

class ID3_Reader{
    public:
        // code omitted for brevity
    protected:
        class Mp3_File;
        Mp3_File mFile;                                             
};

显而易见,它无法编译。我必须在ID3_Reader类中定义Mp3_File类。当我只有两节课时,这不是问题。怎么会有五个呢?我的代码会变得非常混乱。为了避免这个问题,我必须将类声明与它们的定义分开。我怎样才能做到这一点?请记住,我需要ID3_Reader类中的Mp3_File类的实例。 我之所以使用嵌套类,是因为我不想让其他程序员使用Mp3_File类。我使用" protected"关键字,因为我将基于ID3_Reader类创建类。

5 个答案:

答案 0 :(得分:1)

不要将mFile定义为Mp3_File的实例,而是将其定义为指向Mp3_File的指针。这样您就不需要知道头文件中的定义了。或者更好 - 使用智能指针。然后,您需要在类构造函数中使用new并在delete的析构函数中使用ID3_Reader来创建实例。

如果您希望继续使用当前语法从类外部访问mFile,请在访问器函数中取消引用它:

Mp3_File& getMp3(){ return *mFile; };

然后 - 如果Mp3_File过载operator()(或任何其他重载运算符),则无需每次手动取消引用它。

答案 1 :(得分:1)

它不会编译,因为编译器不知道Mp3_File类将使用多少内存。如果将其更改为指针

class ID3_Reader{
    public:
        // code omitted for brevity
    protected:
        class Mp3_File;
        Mp3_File *mFile;                                             
};

编译得很好(指针有一个固定的大小 - http://ideone.com/VmmXfK)。

我建议使用指针而不是完整的成员变量,并在ctor / dtor中初始化/取消初始化它。

我没有看到另一种方法,而没有更改"嵌套类"设计。

答案 2 :(得分:1)

您可以通过使用指针来实现这一点。回想一下,虽然你必须有一个完整的类来定义一个变量,但是一个简单的前向声明可以很好地定义一个指针:

class ID3_Reader{
    public:
        // code omitted for brevity
    protected:
        class Mp3_File;
        Mp3_File *mFile;                                             
};

不幸的是,这会让你处理为嵌套类管理内存的问题,但是它确实隐藏了来自外部程序员的所有类的内部。

答案 3 :(得分:1)

您可以使您的类成为类模板来解决此限制:对于类模板,嵌套类型的定义需要在实例化时可见,而不是在查看类模板的定义时。您可能希望使用typedef来实际命名已使用的实例化,以避免需要尾随<>。这是一个快速演示:

 template <typename = void>
 class ID3_ReaderT {
     public:
         // code omitted for brevity
     protected:
         class Mp3_File;
         Mp3_File mFile;                                             
 };
 typedef ID3_Reader<> ID3_Reader;

 template <typename  T>
 class ID3_ReaderT<T>::Mp3_File {
 };

 int main()
 {
     ID3_Reader reader;
 }

当然,它仍然意味着ID3_Reader的每个用户都需要查看嵌套类型的定义。如果你想避免这种情况,那么你的选择是在级别间接上,即使用多个答案已经说明的指针。

答案 4 :(得分:1)

你可以使用像其他人回答的指针来实现这个目标:

class Mp3_File; // forward declaration of class Mp3_File

class ID3_Reader{
    public:
        // code omitted for brevity
    protected:
        Mp3_File *mFile;                                             
};

或者您可以声明class Mp3_File私有的构造函数并声明class ID3_Reader的{​​{1}} friend

class Mp3_File

因此,其他人无法使用class Mp3_File { Mp3_File() {} // constructor is private friend class ID3_Reader; }; class ID3_Reader{ public: // code omitted for brevity protected: Mp3_File mFile; }; auto main() -> int { ID3_Reader r; Mp3_File m; // Error Mp3_File constructor is private! return 0; } ,而您可以在Mp3_File的范围内使用它。