我知道在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 ++中实现这一点似乎很难。
答案 0 :(得分:2)
您需要转发声明:
class B; // forward declaration
class A
{
B foo();
};
class B
{
A bar();
};
上面的声明告诉编译器class B
存在但不是它的样子。这足以将其用作函数或方法的参数或返回类型。然后你可以跟进实际的定义。
答案 1 :(得分: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中的类似构造等效。
答案 2 :(得分: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() { ... }