-1

我知道在 C++ 中为成员变量递归定义类型的问题:

#include "B.h"
class A
{
    B b;
};

#include "A.h"
class B
{
    A b;
};

编译器对此抱怨,因为不可能以这种递归方式分配内存。

我不明白的是,这似乎也适用于函数定义:

#include "B.h"
class A
{
    B foo();
};

#include "A.h"
class B
{
    A bar();
};

编译器给出了同样的错误:

error: ‘A’ does not name a type
error: ‘B’ does not name a type

这是为什么?编译器需要为返回类型保留空间对我来说没有意义。我应该用指针和前向声明解决这个问题吗?根据我的经验(来自 Java),程序员使用这些递归定义来设计软件是很常见的。在 C++ 中似乎很难实现这一点。

4

3 回答 3

2

你需要一个前向声明

class B;    // forward declaration

class A
{
    B foo();
};

class B
{
    A bar();
};

上面的声明告诉编译器class B存在而不是它的样子。这足以将其用作函数或方法的参数或返回类型。然后你可以跟进实际的定义。

于 2016-08-16T23:30:47.610 回答
2

就函数定义而言,您只需要一个适当的前向声明:

class A;
class B;

class A
{
    B foo();
};

class B
{
    A bar();
};

这将毫无问题地编译。随意将其分成两个单独的头文件,并使用适当的前向声明而不是#include.

请注意,您不能以相同方式声明类成员的原因是因为这将有效地使类包含自身。不幸的是,如果这是可能的,最终结果将是一个巨大的黑洞,它将吞噬我们所知道的所有生命,我们当然不希望这种情况发生......

无论如何,您需要记住的另一点是您在这里受到 Java 背景的影响。尽管语法相似,类在 C++ 中的工作方式与它们在 Java 中的工作方式根本不同。你最好忘记你所知道的关于类如何在 Java 中工作的一切。否则你会一直偏离轨道,就像那样。在 Java 中,一组类似的声明不会导致类有效地包含自身,但在 C++ 中却可以。这是因为在 Java 中,每个类实例实际上都是指向类的指针,但在 C++ 中,它是类本身,有血有肉。

在 C++ 中,这种递归类声明的真正等价物是:

class A
{
    std::shared_ptr<B> b;
};

class B
{
    std::shared_ptr<B> A;
};

(暂时忽略此处也适用的必要前向声明)。

这将在 C++ 中与在 Java 中一样好地工作(这std::shared_ptr<>部分相当于 Java 的对象引用计数,排序)。 相当于您在 Java 中的类似构造。

于 2016-08-16T23:33:20.420 回答
1

我不明白的是,这似乎也适用于函数定义:

编译器可以内联函数,唯一的方法是知道返回类型的确切布局。此外,编译器必须知道如何构造函数的返回类型


注意:编译器不需要知道函数声明的返回类型的完整定义,但是,它需要在定义时知道它。

//file A.h
class B;  //forward declaration

class A
{
    B foo();   //declaration
};

//file A.cpp
#include "B.h"

B A::foo(){ ....  }  //definition

//file B.h
class A; //forward declaration
class B
{
    A bar();  //declaration, works
    A moo() { .... } //Declaration + Definition, Fails to see full definition of `A`
};

//file B.cpp
#include "A.h"

A B::boo() { ... }
于 2016-08-16T23:33:01.333 回答