C++ #include 循环

C++ #include Loop

文件Dog.h

#ifndef DOG_H
#define DOG_H

#include "Cat.h"
//class Cat;

class Dog
{
        Cat c;
};

#endif

文件Cat.h

#ifndef CAT_H
#define CAT_H

#include "Dog.h"
//class Dog;

class Cat
{
        Dog d;
};

#endif

这会导致循环,问题是 类 都需要了解对方;前向声明也不能解决问题。您可以创建 Dog d 或 Cat c 的指针来解决它。

问题:是否真的没有办法不创建指针,即保持代码原样而不重写我想要的代码?

你想做的事是不可能的。您的 class 需要无限 space.

你得到了一个 Dog,它有一个 Cat 成员变量,它有一个 Dog 成员变量,它有一个 Cat 成员变量,它有一个 Dog成员变量...

如果不在某处用指针破坏它,你最终会得到无限递归成员变量占用无限内存,这是不可能的。

请注意,由于无限递归,编译器甚至无法实际计算 DogCat 所需的内存。但是由于 C++ 中的 class 通常不能 0 大小,我们知道它无论如何都会是无限的 space。

其他答案也给出了很好的观点,即 'Chicken and Egg' 必须先定义一个才能定义另一个的问题。


我只想补充一点,相互递归 classes 是一种奇怪的东西,如果你能以其他方式设计它,最好避免。如果您真的必须使用它们,请确保您确实打破了递归性。否则,如果你有一个天真的实现,它的指针会无限相互递归 new 调用,那么你只能将它从编译时由于无限相互递归导致的错误转移到 运行 内存不足和运行时崩溃施工时间。

不,这不可能,与包含文件无关。

原因是如果你创建一个 class 其中包含另一个 class 作为成员(而不是指针),编译器需要为那个 space 添加一些 class进入另一个class。例如,如果您创建这样的内容:

class Dog {
  std::string name;
  std::string owner;
};

class Person {
    Dog pet;
    std::string name;
};

然后上例中 class Person 的实例的大小为 sizeof(std::string) + sizeof(Dog),而 class Dog 的实例的大小为 sizeof(std::string) + sizeof(Dog)尺寸为 sizeof(std::string) * 2;所以 Person 的大小是 sizeof(std::string) * 3(模对齐差异)

换句话说,C++ 中第一个 class 变量(相对于指针)所需的内存被分配 作为 实例的一部分,并且不是指针;这与 structs 的工作方式非常相似。事实上,在 C++ 中 classstruct 关键字之间确实没有实际区别,除了 class 默认是 private 而结构是public.

除了这会导致一个无限的 space 对象(正如 Raphael 所解释的),编译器不会让这种情况发生,如 question 中所解释的那样。当你在 Dog class 中使用它时,他不知道 Cat class,所以它不会因为同样的原因而不起作用:

class B;
class A{
    B b;
};

正如已经指出的那样,您不能直接或间接地定义一个没有间接寻址的成员的对象。

如果您只想使用 . 语法而不是 -> 语法,您可以使用引用而不是指针。例如:

// in Dog.h
class Cat;

class Dog {
public:
    std::unique_ptr<Cat> catp;
    Cat &c;
    Dog ();
    Dog (Cat &);
};

// in Cat.h
class Cat {
public:
    std::unique_ptr<Dog> dogp;
    Dog &d;
    Cat ();
    Cat (Dog &);
}

现在,在您的源代码中,您可以这样做:

#include "Dog.h"
#include "Cat.h"

Dog::Dog () : catp(new Cat(*this)), c(*catp) {}
Cat::Cat () : dogp(new Dog(*this)), d(*dogp) {}

Dog::Dog (Cat &cat) : c(cat) {}
Cat::Cat (Dog &dog) : d(dog) {}