了解 Return 函数类型的 "Mutual Recursion Issue"

Understanding the "Mutual Recursion Issue" for the Return Type of Functions

我知道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

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

您需要前向声明:

class B;    // forward declaration

class A
{
    B foo();
};

class B
{
    A bar();
};

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

What I don't understand is that this seems to apply to function definitions as well:

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


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

//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() { ... }

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

class A;
class B;

class A
{
    B foo();
};

class B
{
    A bar();
};

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

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

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

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

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

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

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

这在 C++ 中的效果与在 Java 中的效果一样好(std::shared_ptr<> 部分相当于 Java 的对象引用计数,排序) . 这个 等同于 Java.

中的类似结构