了解 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.
中的类似结构
我知道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.