C++错误:“第 2 行”尚未宣布
C:\CodeBlocks\kool\praks2\src..\include\circle2.h|8|错误: “Line2”未命名类型| C:\CodeBlocks\kool\praks2\src..\include\circle2.h|17|错误: “Line2”尚未声明| ||=== 构建完成:2 个错误,0 个警告 ===|
Circle2.h:
#ifndef CIRCLE2_H
#define CIRCLE2_H
#include "geometry.h"
class Circle2 {
public:
Vector2 p1;
float r;
Circle2();
Circle2(Vector2 np1, float nr);
float circumference();
float area();
bool contains(Vector2 v);
bool contains(Line2 l); // error is here.
void scale(float factor);
friend ostream& operator <<(ostream& out, const Circle2& cir);
};
#endif // CIRCLE2_H
circle.cpp:
bool Circle2::contains(Line2 l) {
return 0;
}
geometry.h:
#ifndef GEOMETRY_H
#define GEOMETRY_H
// These are needed to use the functions in our library
#include <iostream>
using namespace std;
// Include own headers
// NB! Add your own headers here!
#include "vector2.h"
#include "line2.h"
#include "circle2.h"
#endif // GEOMETRY_H
这是circle2.cpp:
#include "../include/circle2.h"
#include <math.h>
Circle2::Circle2() {
p1 = Vector2();
r = 0;
}
Circle2::Circle2(Vector2 np1, float nr) {
p1 = np1;
r = nr;
}
float Circle2::circumference() {
return 2 * r * M_PI;
}
float Circle2::area() {
return pow(r, 2) * M_PI;
}
bool Circle2::contains(Vector2 v) {
if(p1.distanceFrom(v) <= r) return 1;
return 0;
}
bool Circle2::contains(Line2 l) {
return 0;
}
void Circle2::scale(float factor) {
r *= factor;
}
ostream& operator<<(ostream& out, const Circle2& cir) {
out << "(" << cir.p1 << ", " << cir.r << ")";
return out;
}
line2.cpp:
#include "../include/line2.h"
#include <math.h>
Line2::Line2() {
p1 = Vector2();
p2 = Vector2();
}
Line2::Line2(Vector2 np1, Vector2 np2) {
p1 = np1;
p2 = np2;
}
float Line2::length() {
return p1.distanceFrom(p2);
}
ostream& operator<<(ostream& out, const Line2& line) {
out << "(" << line.p1 << " - " << line.p2 << ")";
return out;
}
line2.h:
#ifndef LINE2_H
#define LINE2_H
#include "geometry.h"
class Line2 {
public:
Vector2 p1;
Vector2 p2;
Line2();
Line2(Vector2 np1, Vector2 np2);
float length();
friend ostream& operator <<(ostream& out, const Line2& line);
};
#endif // LINE2_H
C:\CodeBlocks\kool\praks2\src..\include\circle2.h|8|error:
'Line2' does not name a type|
C:\CodeBlocks\kool\praks2\src..\include\circle2.h|17|error:
'Line2' has not been declared| ||===
Build finished: 2 errors, 0 warnings
===|
circle2.h :
#ifndef CIRCLE2_H
#define CIRCLE2_H
#include "geometry.h"
class Circle2 {
public:
Vector2 p1;
float r;
Circle2();
Circle2(Vector2 np1, float nr);
float circumference();
float area();
bool contains(Vector2 v);
bool contains(Line2 l); // error is here.
void scale(float factor);
friend ostream& operator <<(ostream& out, const Circle2& cir);
};
#endif // CIRCLE2_H
circle.cpp:
bool Circle2::contains(Line2 l) {
return 0;
}
geometry.h:
#ifndef GEOMETRY_H
#define GEOMETRY_H
// These are needed to use the functions in our library
#include <iostream>
using namespace std;
// Include own headers
// NB! Add your own headers here!
#include "vector2.h"
#include "line2.h"
#include "circle2.h"
#endif // GEOMETRY_H
This is circle2.cpp:
#include "../include/circle2.h"
#include <math.h>
Circle2::Circle2() {
p1 = Vector2();
r = 0;
}
Circle2::Circle2(Vector2 np1, float nr) {
p1 = np1;
r = nr;
}
float Circle2::circumference() {
return 2 * r * M_PI;
}
float Circle2::area() {
return pow(r, 2) * M_PI;
}
bool Circle2::contains(Vector2 v) {
if(p1.distanceFrom(v) <= r) return 1;
return 0;
}
bool Circle2::contains(Line2 l) {
return 0;
}
void Circle2::scale(float factor) {
r *= factor;
}
ostream& operator<<(ostream& out, const Circle2& cir) {
out << "(" << cir.p1 << ", " << cir.r << ")";
return out;
}
line2.cpp:
#include "../include/line2.h"
#include <math.h>
Line2::Line2() {
p1 = Vector2();
p2 = Vector2();
}
Line2::Line2(Vector2 np1, Vector2 np2) {
p1 = np1;
p2 = np2;
}
float Line2::length() {
return p1.distanceFrom(p2);
}
ostream& operator<<(ostream& out, const Line2& line) {
out << "(" << line.p1 << " - " << line.p2 << ")";
return out;
}
line2.h:
#ifndef LINE2_H
#define LINE2_H
#include "geometry.h"
class Line2 {
public:
Vector2 p1;
Vector2 p2;
Line2();
Line2(Vector2 np1, Vector2 np2);
float length();
friend ostream& operator <<(ostream& out, const Line2& line);
};
#endif // LINE2_H
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您目前已拥有一切并试图包含其他所有内容。这会给你带来麻烦。
看起来 Line2 需要了解 Vector2; Circle2 需要了解 Line2 和 Vector2。 Vector2 是独立存在的,还是尝试使用 Line2 或 Circle2?
如果它独立存在,那么您只需让 Line2 包含 Vector2,并且 Circle2 包含 Line2 和 Vector2。然后删除其他让您绕圈的 include 语句(例如 Circle2 包含几何图形,而几何图形又包含 Circle2...)。
如果 Vector2 尝试使用 Line2 或 Circle2,则会产生循环依赖。下面是解决这个问题的方法:
#include
语句(只是你的几何/Circle2/等)Line2
,而是采用const Line2&
)#include
您需要的形状。其工作方式是头文件不再依赖于其他形状,因此它打破了循环包含循环。
Circle2.cpp
包含Line2.h
,但Line2.h
不包含Circle2.h
,因此循环就此结束。向前声明该类告诉编译器“有一个名为
Line2
的类,但您还不需要知道有关它的任何详细信息”。更改方法以使用引用(或指针)使编译器在处理标头时不需要任何类详细信息。当编译器处理源代码时(您实际上将在其中对另一个类执行某些操作),它现在需要了解另一个类的详细信息。这就是为什么您需要在源文件中包含完整的类定义。
编辑:对包含防护和循环包含发生的情况进行更多解释。
我将使用最简单的情况: Ah 包含 Bh 和 Bh 包含 Ah
当您尝试编译 A.obj 时,预处理器会加载所有包含语句,并且基本上将包含的文件剪切粘贴到源文件中(然后将结果交给编译器)。因此,这是将被处理的顺序:
A.cpp
中,它到达#include "Ah"
,在那里它跳出 A.cpp,并加载 Ah#ifndef A_H
。既然还没有确定,那就继续。Ah
中,它到达#define A_H
。现在就这样了。Ah
中,它到达#include "Bh"
,在那里它跳出 Ah,并加载 BhBh
中,它到达包含守卫对于未设置的B_H
,并设置它。Bh
中,它到达#include "Ah"
,在那里它跳出 Bh 并再次加载 Ah。Ah
中,它到达 <代码>#ifdef A_H。由于 IS 设置,它会跳过直到文件末尾的#endif
。Bh
,预处理继续。所以你可以在这里看到
Bh
甚至不需要包含Ah
,因为无论如何它什么也没做。但如果你尝试将其取出,那么 B.obj 将无法编译。当您尝试编译 B.obj 时,Ah
不需要包含Bh
。这会导致一个奇怪的情况:A.obj
时,编译器会在Ah
之前看到Bh
中的声明。B.obj
时,编译器会看到Bh
之前的Ah
中的声明。为了使其发挥作用,必须满足两件事:
A.obj
,编译器必须能够编译Bh
而无需Ah
>B.obj
,编译器必须能够编译Ah
而无需Bh
因此,要构建整个项目,Ah 和 Bh实际上不能互相依赖。这就是前瞻性声明的重要性发挥作用的地方。您可以在此处告诉 Bh 有关
class A;
的信息 - 而无需实际使用 include 语句。当然,您必须遵循前向声明的规则 - 只能引用或指针,不能取消引用。请注意,如果您添加前向声明,而不删除
#include
语句,您的项目将会构建。因为(如我上面所示),有时#include
语句不执行任何操作。我希望事情能够澄清。
You've currently got everything trying to include everything else. This will get you into trouble.
It looks like Line2 needs to know about Vector2; and Circle2 needs to know about both Line2 and Vector2. Does Vector2 stand on its own, or does it try to use Line2 or Circle2?
If it stands on its own, then you simply need to have Line2 include Vector2, and Circle2 include Line2 and Vector2. Then remove the other include statements that have you running around in circles (e.g. Circle2 includes geometry which includes Circle2...).
If Vector2 tries to use Line2 or Circle2, you'll have a circular dependency. Here's how to solve that:
#include
statements from the header files (just your geometry/Circle2/etc)Line2
, takeconst Line2&
)#include
the header files of the shapes you need.The way this works is that the header files no longer have a dependency on the other shapes, so it breaks the circular include cycle.
Circle2.cpp
includesLine2.h
, butLine2.h
doesn't includeCircle2.h
, so the cycle ends there.Forward declaring the class tells the compiler "there is a class called
Line2
, but you don't need to know any details about it yet". Changing the methods to use references (or pointers) allows the compiler to not need any class details when processing the header.When the compiler processes the source (where you'll actually do something with the other class), it now needs to know the details of the other class. This is why you need to include the full class definition in the source file.
EDIT: a little more explanation about what happens with include guards and circular includes.
I'll use the simplest case: A.h includes B.h and B.h includes A.h.
When you attempt to compile A.obj, the preprocessor loads all the include statements, and basically does a cut-n-paste of the included file into the source file (and then hands the result to the compiler). So here's the order this will be processed:
A.cpp
, it reaches#include "A.h"
, where it jumps out of A.cpp, and loads A.hA.h
, it reaches#ifndef A_H
. Since that's not set, it continues.A.h
, it reaches#define A_H
. Now that's set.A.h
, it reaches#include "B.h"
, where it jumps out of A.h, and loads B.hB.h
, it reaches the include guard forB_H
, which wasn't set, and sets it.B.h
, it reaches#include "A.h"
, where it jumps out of B.h and loads A.h (again)A.h
, it reaches#ifdef A_H
. Since that IS set, it skips until#endif
- at the end of the file.B.h
, preprocessing continues.So you can see here that
B.h
didn't even need to includeA.h
, since that did nothing anyway. But if you try to take it out, then B.obj won't compile. And when you try to compile B.obj,A.h
doesn't need to includeB.h
. This leads to a weird scenario:A.obj
, the compiler will see the declarations inB.h
beforeA.h
.B.obj
, the compiler will see the declarations inA.h
beforeB.h
.In order for this to work, two things must be true:
A.obj
, the compiler has to be able to compileB.h
withoutA.h
B.obj
, the compiler has to be able to compilerA.h
withoutB.h
So, to build your whole project, A.h and B.h can't actually rely on including each other. This is where the importance of forward declarations comes into play. This is where you can tell B.h about
class A;
- without actually using the include statement. Of course you have to follow the rules for forward declarations - only references or pointers, no dereferencing.Note that if you add the forward declaration, without removing the
#include
statements, your project will build. Because (as I showed above), sometimes that#include
statement does nothing.I hope that clears things up.
你可以尝试
在之前添加:
you can try to add:
before the
确保您已#included Line2 类的定义。
Make sure you've #included a definition of the Line2 class.