3

有人能够解释为什么头文件有这样的东西吗?

class foo; // This here?
class bar
{
   bar();

};

使用它时是否需要包含语句?

谢谢。

4

9 回答 9

10

第一个class foo;称为类 foo 的前向声明。它只是让编译器知道它存在并且它命名了一个类。这使得 foo 成为所谓的“不完整类型”(除非已经看到 foo 的完整声明)。对于不完整类型,您可以声明该类型的指针,但您不能分配该类型的实例或执行任何需要知道其大小或成员的操作。

这样的前向声明经常在两种类型可能有彼此的指针时使用,在这种情况下,两者都需要能够表达指向另一种类型的指针的概念,因此如果没有这样的东西,您将有一个循环依赖。这主要是因为 C++ 使用单通道机制来解析类型。在 Java 中,您可以在没有前向声明的情况下拥有循环依赖,因为 Java 使用多次传递。您可能还会看到前向声明,作者误以为使用前向声明而不是包含所需的头文件会减少编译时间;当然,情况并非如此,因为无论如何您都需要包含完整的声明(即标头),并且如果使用了预处理器保护,那么编译时间基本上没有区别。

要回答您是否需要包含的问题...假设您只需要部分类型,那么您的标头不需要直接包含已前向声明的类型的标头;但是,无论谁使用您的标头,当他们使用您的类型时,都需要包含前向声明类型的标头,因此您不妨只包含另一个标头。

于 2010-04-28T10:18:12.397 回答
2

那是一个前向声明。例如,如果类 bar 有一个指向 foo 对象的指针,但您不想立即包含 foo 对象的整个定义,则需要它。

于 2010-04-28T10:17:21.400 回答
1

只是好奇,为什么我们需要术语前向声明?前向声明不是简单的声明(与定义相反)吗?

class X;  // declaration

class X   // definition
{
    int member;
    void function();
};
于 2010-04-28T11:00:40.653 回答
1

这是类的前向声明。以我的经验,这通常是在您有循环依赖时完成的。例如

in foo.h
--------
#include "bar.h"

class foo
{
public:
    foo(bar *bar);
private:
    foo *m_foo;
};

and in bar.h
------------
class foo;
class bar
{
public:
    void methodFooWillCall();
protected:
    std::list<foo *> myFoos;
}
于 2010-04-28T10:17:35.780 回答
0

试着想想写这个:

文件 bar.h:

        #include "bar.h"

        class Foo
        {
        Bar* bar_ptr;
        }

文件 foo.h:

        #include "foo.h"

        class Bar
        {
            Foo* foo_ptr;
        }

这不起作用,首先是由于无限的#include 链,然后如果你摆脱其中一个包含,要么 Foo 不知道 Bar 是什么,要么 Bar 不知道 Foo 是什么。

试试这个:

        class Bar;

        class Foo
        {
        Bar* bar_ptr;
        };

文件 foo.h:

        class Foo;

        class Bar
        {
            Foo* foo_ptr;
        };
于 2010-04-28T15:03:22.767 回答
0

这是一个前瞻性声明。考虑以下示例:

class foo; // you likely need this for the code beneath to compile
class bar {
    void smth( foo& );
};

如果您没有class foo以编译器在编译之前看到它的方式包含定义,则除非您有前向声明,否则class bar代码的定义将无法编译(编译器会说它不知道是什么意思)。foo

于 2010-04-28T10:17:29.977 回答
0

这是“foo”类的前向声明。它允许您声明类的指针和引用,但不能使用它(例如,调用成员或确定其大小),因为它尚未定义!之后必须进行完整、正常的声明 ( class foo { ... };)。

它对于诸如声明两个持有彼此指针的类之类的事情很有用,否则将无法设置。

于 2010-04-28T10:17:40.377 回答
0

这称为前向声明。类的主体foo将在文件的后面部分定义。前向声明是为了绕过循环依赖:类 Bar 的定义需要类 Foo ,反之亦然。

class Bar
{
   Foo * foo;
};
class Foo
{
   Bar * bar;
};

如您所见,Bar具有引用,Foo反之亦然。如果你尝试编译它,编译器会抱怨说它对Foo. 解决方案是转发声明class Foo上面的Bar(就像你在上面声明一个函数的原型main并稍后定义它的主体)。

class Foo; //Tells the compiler that there is a class Foo coming down the line.
class Bar
{
   Foo * foo;
};
class Foo
{
   Bar * bar;
};
于 2010-04-28T10:18:55.210 回答
0

这称为前向声明。它用于使您的代码知道类 foo 存在。这反过来可以被类栏使用。

它通常用于解决循环包含问题。以此为例

//a.h
#include "b.h"

class A
{
    void useB(B obj);
}

// b.h
#include "a.h"
class B
{
     void useA(A obj);
}

这会导致循环包含问题,因为 ah 包含 bh,而 bh 又包含 ah,直到无穷大。您可以通过在每个标头中对每个类进行前向声明来解决此问题,如下所示:

//a.h
class B;

class A
{
    void useB(B obj);
}

// b.h
class A;

class B
{
     void useA(A obj);
}

注意:通常当您遇到循环包含问题时,这表明存在概念/建模问题。在尝试使用前向声明解决问题之前,您可能应该问问自己您的类是否定义明确。

于 2010-04-28T10:20:14.700 回答