C++ 类转发声明失败

C++ 类转发声明失败,c++,C++,我有两个头文件和一个源文件 食物.h: #ifndef _FOOD_H #define _FOOD_H struct food { char name[10]; }; #endif 狗。h: #ifndef _DOG_H #define _DOG_H class food; //forward declaration class Dog { public: Dog(food f); private: food _f; }; #endif 这是类狗的源文件

我有两个头文件和一个源文件

食物.h:

#ifndef _FOOD_H
#define _FOOD_H

struct food {
    char name[10];
};

#endif
狗。h:

#ifndef _DOG_H
#define _DOG_H

class food;  //forward declaration

class Dog {
public:
    Dog(food f);

private:
    food _f;
};

#endif
这是
类狗的源文件

//dog.cpp
#include "dog.h"
#include "food.h"

Dog::Dog(food f) : _f(f)
{}
问题是我可以编译上面的代码,我得到一个错误,说
\u f的类型不完整


我想我可以在
dog.h
中提出声明,并在
dog.cpp
中包含
food.h
,但它不起作用,为什么?我不应该把用户定义的头文件放在
.h
文件中,对吗?它已经被弃用了,不是吗?

编译器需要知道对象的大小
\u f
,而仅使用正向声明无法访问该对象。如果您使用指向
类食物的指针
,这将起作用,但由于您的成员是完整的类实例,您需要包含标题,以便编译器可以知道
类食物的大小

类似地,如果继承自
食品类
,则转发声明将不起作用-您将特别需要包含标题


只需删除转发声明并包含“food.h”,您的代码就会编译。

编译器需要知道仅使用转发声明无法访问的对象的大小。如果您使用指向
类食物的指针
,这将起作用,但由于您的成员是完整的类实例,您需要包含标题,以便编译器可以知道
类食物的大小

类似地,如果继承自
食品类
,则转发声明将不起作用-您将特别需要包含标题


只需删除转发声明并包含“food.h”,您的代码就会编译。

转发声明在这种情况下不起作用,因为您的
Dog
类有一个
food
的实例。编译器需要完整声明
食物
,才能声明

至于反对包含的问题,除非我误解了什么,否则它根本不是真的。在这里添加
food.h
可以解决您的问题:

//dog.h
#ifndef DOG_H
#define DOG_H

#include "food.h";

class Dog {
public:
    Dog(food f);

private:
    food f_;
};

转发声明在这种情况下不起作用,因为您的
Dog
类有一个
food
实例。编译器需要完整声明
食物
,才能声明

至于反对包含的问题,除非我误解了什么,否则它根本不是真的。在这里添加
food.h
可以解决您的问题:

//dog.h
#ifndef DOG_H
#define DOG_H

#include "food.h";

class Dog {
public:
    Dog(food f);

private:
    food f_;
};


将“food.h”包含在您的
dog.h
中。这是必要的,一点也不反对。旁注:你不应该在include guarders(
\ifndef\u FOOD\u H…
)中使用前导下划线,因为它在某些上下文中是保留的,所以只要使用
\ifndef FOOD\u H…
@LokiAstari,即使有
FOOD
数据成员?@KerrekSB,但是有人告诉我,如果一个用户定义的文件被更改,那么在其他头中包含用户定义的头可能会增加编译时间。如果您通过引用传递食物(并且成员是引用),那么编译器不需要知道大小,因此转发声明将起作用。否则它需要知道大小,因此您需要在使用前包含头文件。将
#include“food.h”
放入您的
dog.h
。这是必要的,一点也不反对。旁注:你不应该在include guarders(
\ifndef\u FOOD\u H…
)中使用前导下划线,因为它在某些上下文中是保留的,所以只要使用
\ifndef FOOD\u H…
@LokiAstari,即使有
FOOD
数据成员?@KerrekSB,但是有人告诉我,如果一个用户定义的文件被更改,那么在其他头中包含用户定义的头可能会增加编译时间。如果您通过引用传递食物(并且成员是引用),那么编译器不需要知道大小,因此转发声明将起作用。否则它需要知道大小,因此您需要在使用前包含头文件。是的,包含
food.h
可以解决问题,但是如果包含的文件被更改,则包含用户定义的头文件可能包括编译时间,对吗?@Alcott确实如此。如果您在
food.h
中更改了某些内容,那么依赖它的所有代码都必须重新编译。最好尽量减少包含,并尽可能使用前向声明,但在这种情况下不能(除非您更改
Dog
,使其不包含
food
实例)。老实说,我不太理解编译器在声明类
Dog
时是如何工作的。我想它会先把
dog.h
展开成
dog.cpp
,然后开始解释类
dog
的定义,如果那样的话,它应该知道
food
是什么样子的,因为我在
dog.cpp
@mikeseymour中包含了
food.h
,定义中的尾随下划线有问题吗?我以为只为实现保留了前导下划线。@Alcott头提供了编译时代码客户机所需的一组信息。这包括函数和类声明。类中包含的类的完整声明是必需的信息之一。是的,包括
food.h
可以解决问题,但是如果包含的文件被更改,包括用户定义的头可能包括编译时,对吗?@Alcott确实如此。如果您在
food.h
中更改了某些内容,那么依赖它的所有代码都必须重新编译。最好尽量减少包含,并尽可能使用前向声明,但在这种情况下不能(除非您更改
Dog
,使其不包含
food
实例)。老实说,我不太理解编译器在声明类
Dog
时是如何工作的。我以为它会先展开
dog.h