C ++错误:'Line2'尚未声明

时间:2011-02-20 16:36:54

标签: c++ codeblocks

  

C:\码块\库尔\ praks2 \ SRC .. \包括\ circle2.h | 8 |错误:   'Line2'没有命名类型|   C:\代码块\库尔\ praks2的\ src .. \包括\ 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

3 个答案:

答案 0 :(得分:2)

你现在已经尝试了其他所有内容。这会让你陷入麻烦。

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

如果它独立,那么你只需要让Line2包含Vector2,而Circle2包含Line2和Vector2。然后删除在圆圈中运行的其他包含语句(例如,Circle2包含包含Circle2的几何图形......)。

如果Vector2尝试使用Line2或Circle2,则您将具有循环依赖关系。以下是解决这个问题的方法:

  • 从标题文件中删除#include语句(只是几何/ Circle2 /等)
  • 转发声明每个标题中需要的类(参见Baget的答案)
  • 更改方法签名以将常量引用作为参数(例如,取代Line2,取const Line2&
  • 在源文件中,#include您需要的形状的头文件。

这种方式的工作方式是头文件不再依赖于其他形状,因此它打破了循环包含循环。 Circle2.cpp包括Line2.h,但Line2.h不包含Circle2.h,因此周期结束。

前向声明该类告诉编译器“有一个名为Line2的类,但您还不需要知道它的任何细节”。更改方法以使用引用(或指针)允许编译器在处理标头时不需要任何类详细信息。

当编译器处理源代码(您实际上在其他类中执行某些操作)时,它现在需要知道另一个类的详细信息。这就是您需要在源文件中包含完整的类定义的原因。

编辑:关于包含警卫和循环包含会发生什么的更多解释。

我将使用最简单的案例:A.h包括B.h和B.h包括A.h。

当您尝试编译A.obj时,预处理器会加载所有include语句,并且基本上将包含文件的剪切粘贴到源文件中(然后将结果交给编译器)。所以这是处理的顺序:

  • A.cpp中,它到达#include "A.h",跳出A.cpp,并加载A.h
  • A.h中,它达到#ifndef A_H。由于没有设定,它会继续。
  • A.h中,它达到#define A_H。现在已经确定了。
  • A.h中,它到达#include "B.h",从A.h跳出,然后加载B.h
  • B.h中,它会到达未设置的B_H的包含守卫并设置它。
  • B.h中,它到达#include "A.h",跳出B.h并加载A.h(再次)
  • A.h中,它达到#ifdef A_H。自设置 IS 以来,它会跳过#endif - 文件末尾。
  • 返回B.h,继续预处理。

因此,您可以在此处看到B.h甚至不需要包含A.h,因为无论如何都没有做任何事情。但如果你试图把它拿出来,那么B.obj就不会编译。当您尝试编译B.obj时,A.h不需要包含B.h。这导致了一个奇怪的情况:

  • 编译A.obj时,编译器将在B.h之前的A.h中看到声明。
  • 编译B.obj时,编译器将在A.h之前的B.h中看到声明。

为了实现这一点,必须做到两件事:

  • 编译A.obj,编译器必须能够编译B.h而不A.h
  • 编译B.obj,编译器必须能够编译A.h而不用B.h

因此,为了构建整个项目,A.h和B.h实际上并不能依赖于相互包容。这就是前瞻性声明的重要性发挥作用的地方。在这里您可以告诉B.h关于class A; - 而不实际使用include语句。当然,你必须遵循前向声明的规则 - 只有引用或指针,没有解除引用。

请注意,如果添加前向声明而不删除#include语句,则会构建项目。因为(如上所示),有时候#include语句什么都不做。

我希望能够解决问题。

答案 1 :(得分:1)

您可以尝试添加:

class Line2;

之前的

class Circle2 {

答案 2 :(得分:0)

确保你已经#included了Line2类的定义。