可以说具有如下通用代码:
y.hpp:
#ifndef Y_HPP
#define Y_HPP
// LOTS OF FILES INCLUDED
template <class T>
class Y
{
public:
T z;
// LOTS OF STUFF HERE
};
#endif
现在,我们希望能够在我们创建的类(比如 X)中使用 Y。但是,我们不希望 X 的用户必须包含 Y 标头。
所以我们定义了一个类 X,如下所示:
x.hpp:
#ifndef X_HPP
#define X_HPP
template <class T>
class Y;
class X
{
public:
~X();
void some_method(int blah);
private:
Y<int>* y_;
};
#endif
注意,因为 y_ 是一个指针,我们不需要包含它的实现。
实现在 x.cpp 中,单独编译:
x.cpp:
#include "x.hpp"
#include "y.hpp"
X::~X() { delete y_; }
void X::someMethod(int blah) { y_->z = blah; }
所以现在我们的客户可以只包含“x.hpp”来使用X,而不需要包含并且必须处理所有的“y.hpp”头文件:
main.cpp:
#include "x.hpp"
int main()
{
X x;
x.blah(42);
return 0;
}
现在我们可以单独编译main.cpp
和编译了,编译时我不需要包含.x.cpp
main.cpp
y.hpp
但是,对于这段代码,我不得不使用原始指针,此外,我不得不使用删除。
所以这是我的问题:
(1)有没有一种方法可以使 Y 成为 X 的直接成员(而不是指向 Y 的指针),而无需包含 Y 标头?(我强烈怀疑这个问题的答案是否定的)
(2)有没有办法可以使用智能指针类来处理堆分配的 Y?unique_ptr
似乎是显而易见的选择,但是当我改变线路时x.hpp
从:
Y<int>* y_;
到:
std::unique_ptr< Y<int> > y_;
并包含,并使用 c++0x 模式编译,我收到错误:
/usr/include/c++/4.4/bits/unique_ptr.h:64: error: invalid application of ‘sizeof’ to incomplete type ‘Y<int>’
/usr/include/c++/4.4/bits/unique_ptr.h:62: error: static assertion failed: "can't delete pointer to incomplete type"
那么有没有办法通过使用标准智能指针而不是原始指针以及自定义析构函数中的原始删除来做到这一点?
解决方案:
Howard Hinnant 做对了,我们需要做的就是x.hpp
按照x.cpp
以下方式进行更改:
x.hpp:
#ifndef X_HPP
#define X_HPP
#include <memory>
template <class T>
class Y;
class X
{
public:
X(); // ADD CONSTRUCTOR FOR X();
~X();
void some_method(int blah);
private:
std::unique_ptr< Y<int> > y_;
};
#endif
x.cpp:
#include "x.hpp"
#include "y.hpp"
X::X() : y_(new Y<int>()) {} // ADD CONSTRUCTOR FOR X();
X::~X() {}
void X::someMethod(int blah) { y_->z = blah; }
我们很适合使用 unique_ptr。谢谢霍华德!
解决方案背后的理由:
如果我错了,人们可以纠正我,但这段代码的问题是隐式默认构造函数试图默认初始化 Y,因为它对 Y 一无所知,所以它不能这样做。通过明确地说我们将在别处定义一个构造函数,编译器认为“好吧,我不必担心构造 Y,因为它是在别处编译的”。
真的,我应该首先添加一个构造函数,没有它我的程序是错误的。