尽管 #ifndef,但包含两次头文件



我有一个类角度,<<运算符重载,还有两个包含头文件的 cpp 文件。我有一个 #ifndef 语句来防止多次包含该文件。但是,它似乎被多次包含,因为我收到一个错误,即多次定义运算符<<。然后,我添加了一个 #warning,以查看何时包含该文件。在编译器输出中,可以看到 #warning 被处理了两次。如果我将定义移动到 cpp 文件,它显然可以工作,但我仍然觉得这种情况下的行为很奇怪。

在我看来,编译器不应该两次处理头文件。这种行为有什么原因吗?

主.cpp

#include <iostream>
#include <cmath>
#include <cstdlib>
#include "Angle.h"
using namespace std;
int main() {
    Angle a = (Angle)(M_PI/4);
    cout << a << endl;
    return EXIT_SUCCESS;
}

角度.h

#ifndef ANGLE_ANGLE_H
#define ANGLE_ANGLE_H
#include <iostream>
class Angle {
private:
    double value;
public:
    explicit Angle (double value) {this->value = value; }
    double getValue() const {return this->value;}
    // Operators
    operator const double() const {
        return this->value;
    }
};
#warning INCLUDING_ANGLE_H
std::ostream& operator << (std::ostream& os, const Angle& obj){
    os << obj.getValue();
    return os;
}
#endif //ANGLE_ANGLE_H

角度.cpp

#include "Angle.h"

我正在使用以下命令进行编译:

g++ main.cpp Angle.cpp -o angle

出现以下错误:

In file included from main.cpp:5:0:
Angle.h:19:2: warning: #warning INCLUDING_ANGLE_H [-Wcpp]
 #warning INCLUDING_ANGLE_H
  ^
In file included from Angle.cpp:1:0:
Angle.h:19:2: warning: #warning INCLUDING_ANGLE_H [-Wcpp]
 #warning INCLUDING_ANGLE_H
  ^
/tmp/cci53Hrd.o: In function `operator<<(std::ostream&, Angle const&)':
Angle.cpp:(.text+0x0): multiple definition of `operator<<(std::ostream&, Angle const&)'
/tmp/ccBbwtlD.o:main.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

问题不在于标头被包含两次,而在于该函数被定义了两次。在.cpp文件中定义它,并将 extern 添加到标头中的前向声明中,一切都应该可以正常工作。问题是每次包含标头时,它都会创建函数的新实现,并且您会收到一个链接器错误,它不知道要使用哪个链接器错误。这就是为什么你不应该在标头中实现全局函数,而是应该在.cpp中实现全局函数。

您的 Angle.h 将具有:

extern std::ostream& operator << (std::ostream& os, const Angle& obj);

而角度.cpp将具有:

std::ostream& operator << (std::ostream& os, const Angle& obj){
  os << obj.getValue();
  return os;
}

编译时多次包含头文件是完全正常的。#ifndef只会在同一编译过程中隔离多个包含,即同一个.cpp文件。

编译阶段通常将多个.cpp文件编译为中间形式,然后链接在一起形成单个库或可执行文件。

如果需要为每个目标定义一次函数,则必须将该代码移动到单个.cpp文件中。将其包含在标头中可能会导致重复。

相关内容

最新更新