当你不想#include时替代前向声明

sha*_*kin 10 c++ physical-design forward-declaration

我通常几乎不再思考,使用前向声明,这样我就不必包含标题.这个例子的东西:

//-----------------------
// foo.h
//-----------------------
class foo
{
   foo();
   ~foo();
};


//-----------------------
// bar.h
//-----------------------

class foo; // forward declaration

class bar
{
   bar();
   ~bar();

   foo* foo_pointer;
};
Run Code Online (Sandbox Code Playgroud)

一些开发人员喜欢使用此方法来避免包含圈子的问题.我宁愿用它来减少广泛的包含层次结构的开销,这是物理设计的一个重要部分(特别是对于大型项目).

但是,在某些情况下,我真的想将成员声明为普通对象而不是指针,以便从自动构建/销毁机制中受益.这导致了前向声明不能再使用的问题,因为在这种情况下编译器需要类定义,例如:

//-----------------------
// foo.h
//-----------------------
class foo
{
   foo();
   ~foo();
};


//-----------------------
// bar.h
//-----------------------

class foo;       // Not enough given the way we declare "foo_object"..
#include "foo.h" // ..instead this is required

class bar
{
   bar();
   ~bar();

   foo foo_object;
};
Run Code Online (Sandbox Code Playgroud)

所以,如果有人知道可以在这里使用的替代语言构造,我会很高兴我可以声明"foo_object",如示例中所示,但不包括其标题.

问候

/罗伯特·

Pie*_*ter 12

你不能.在声明类时,编译器需要知道对象的大小.

引用是一种替代方法,尽管它们必须在构造时实例化,因此并不总是可行的.

另一种选择是智能指针,但我认为技术上仍然是一个指针.

很高兴知道为什么你不想使用指针建议其他构造虽然......


Tyl*_*nry 7

你想要什么不能在C++中完成.为了生成对象的代码,您的编译器需要知道它的类需要多少存储空间.为了解这一点,它必须知道每个类成员需要多少存储空间.

如果要创建一个类型为bar的类型为bar的类型,编译器必须知道foo有多大.它知道的唯一方法是它是否有可用的foo定义(通过#include).否则,您唯一的选择是使用foo的前向声明和指针或引用而不是实际的foo对象.


Ecl*_*pse 7

只需使用智能指针 - 在这种情况下甚至可以使用auto_ptr.

//-----------------------
// bar.h
//-----------------------

#include <memory>
class foo;       // Not enough given the way we declare "foo_object"..

class bar
{
public:
   bar();
   ~bar();

   foo &foo_object() { return *foo_ptr; }
   const foo &foo_object() const { return *foo_ptr; }

private:
   auto_ptr<foo> foo_ptr;
};
Run Code Online (Sandbox Code Playgroud)

您可以获得自动内存管理的所有好处,而无需在bar.h中了解有关foo的任何信息.请参阅为Herb Sutter建议包装指针数据成员.

如果您确实希望默认构造自动发生,请尝试以下方法:

#include <iostream>
using namespace std;

class Foo;

template <typename T>
class DefaultConstuctorPtr
{
    T *ptr;
    void operator =(const DefaultConstuctorPtr &);
    DefaultConstuctorPtr(const DefaultConstuctorPtr &);

public:
    DefaultConstuctorPtr() : ptr(new T()) {}
    ~DefaultConstuctorPtr() { delete ptr; }

    T *operator *() { return ptr; }
    const T *operator *() const { return ptr; }
};

class Bar
{
    DefaultConstuctorPtr<Foo> foo_ptr;
public:
    Bar() {} // The compiler should really need Foo() to be defined here?
};

class Foo
{
public:
    Foo () { cout << "Constructing foo"; }
};

int main()
{
    Bar bar;
}
Run Code Online (Sandbox Code Playgroud)