是否可以将类声明与其定义分开?当然是,但是如果我想在它的实际定义之前拥有这个类的对象呢?请考虑以下示例:
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类创建类。
答案 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
的范围内使用它。