C++错误:“第 2 行”尚未宣布

发布于 2024-10-18 10:04:51 字数 2715 浏览 4 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情愿 2024-10-25 10:04:51

您目前已拥有一切并试图包含其他所有内容。这会给你带来麻烦。

看起来 Line2 需要了解 Vector2; Circle2 需要了解 Line2 和 Vector2。 Vector2 是独立存在的,还是尝试使用 Line2 或 Circle2?

如果它独立存在,那么您只需让 Line2 包含 Vector2,并且 Circle2 包含 Line2 和 Vector2。然后删除其他让您绕圈的 include 语句(例如 Circle2 包含几何图形,而几何图形又包含 Circle2...)。

如果 Vector2 尝试使用 Line2 或 Circle2,则会产生循环依赖。下面是解决这个问题的方法:

  • 从头文件中删除 #include 语句(只是你的几何/Circle2/等)
  • 向前声明每个头文件中你需要的类(参见Baget的答案)
  • 将方法签名更改为 在源文件中采用常量引用作为参数(例如,不采用 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
  • In < code>啊,到达#ifndef A_H。既然还没有确定,那就继续。
  • Ah中,它到达#define A_H。现在就这样了。
  • Ah 中,它到达 #include "Bh",在那里它跳出 Ah,并加载 Bh
  • Bh 中,它到达包含守卫对于未设置的 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:

  • remove the #include statements from the header files (just your geometry/Circle2/etc)
  • forward declare the classes you need in each header (see Baget's answer)
  • change the method signature to take a constant reference as a parameter (e.g. instead of taking Line2, take const Line2&)
  • in the source files, #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 includes Line2.h, but Line2.h doesn't include Circle2.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:

  • In A.cpp, it reaches #include "A.h", where it jumps out of A.cpp, and loads A.h
  • In A.h, it reaches #ifndef A_H. Since that's not set, it continues.
  • In A.h, it reaches #define A_H. Now that's set.
  • In A.h, it reaches #include "B.h", where it jumps out of A.h, and loads B.h
  • In B.h, it reaches the include guard for B_H, which wasn't set, and sets it.
  • In B.h, it reaches #include "A.h", where it jumps out of B.h and loads A.h (again)
  • In A.h, it reaches #ifdef A_H. Since that IS set, it skips until #endif - at the end of the file.
  • Back to B.h, preprocessing continues.

So you can see here that B.h didn't even need to include A.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 include B.h. This leads to a weird scenario:

  • when you compile A.obj, the compiler will see the declarations in B.h before A.h.
  • when you compile B.obj, the compiler will see the declarations in A.h before B.h.

In order for this to work, two things must be true:

  • to compile A.obj, the compiler has to be able to compile B.h without A.h
  • to compile B.obj, the compiler has to be able to compiler A.h without B.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.

酸甜透明夹心 2024-10-25 10:04:51

你可以尝试

class Line2;

在之前添加:

class Circle2 {

you can try to add:

class Line2;

before the

class Circle2 {
著墨染雨君画夕 2024-10-25 10:04:51

确保您已#included Line2 类的定义。

Make sure you've #included a definition of the Line2 class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文