C ++包含后卫似乎不起作用?

时间:2012-09-07 14:45:57

标签: c++ file header include guard

我之前曾多次使用过包含警卫,但从未真正理解他们的工作方式或原因。

为什么以下不起作用?

#ifndef CAMERA_CLASS_HPP
#define CAMERA_CLASS_HPP


class camera_class
{
....
};

camera_class glcam = camera_class();


#endif // CAMERA_CLASS_HPP

错误是这样的:(您可以从这个问题的标题中猜出它会是什么!)

-------------- Build: Debug in System ---------------

Linking console executable: bin/Debug/System
/usr/bin/ld: error: obj/Debug/main.o: multiple definition of 'glcam'
/usr/bin/ld: obj/Debug/camera_class.o: previous definition here
/usr/bin/ld: error: obj/Debug/main.glfunc.o: multiple definition of 'glcam'
/usr/bin/ld: obj/Debug/camera_class.o: previous definition here
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)
0 errors, 0 warnings

另外,有人可以向我解释为什么头部防守工作吗?

6 个答案:

答案 0 :(得分:8)

标题保护将防止单个翻译单元中的多个包含。标题可以(并且正在)包含在多个翻译单元中:

// a.cpp:
#include "camera.hpp"

// b.cpp
#include "camera.hpp"

这将产生a.objb.obj,每个glcam包含glcam的定义。当链接在一起产生最终二进制时,您会得到多重定义错误。

您需要在标头中声明 .cpp,并在// camera.hpp ... extern camera_class glcam; // camera.cpp #include "camera.hpp" camera_class glcam; 文件中定义一次:

{{1}}

答案 1 :(得分:4)

根本原因:
标题保护可以防止在同一 translation unit 中多次包含相同的标题,但不能跨越不同的翻译单元。当您在多个翻译单元中包含相同的头文件时,然后,
确实会在包含标题的每个翻译单元中创建glcam的副本 C ++标准要求每个符号只能 defined 一次( One Definition Rule )因此链接器会向您发出错误。

<强>解决方案:
不要在头文件中创建glcam。相反,它应该以这样的方式创建,即它只被定义一次。正确的方法是 using the keyword extern

答案 2 :(得分:3)

看起来您想创建一个可以在多个地方使用的glcam个对象。我会通过公开一个自由函数来返回一个static实例。这与使用extern类似,但我发现它的意图更加明确。

#ifndef CAMERA_CLASS_HPP
#define CAMERA_CLASS_HPP


class camera_class
{
....
};

camera_class& get_camera();


#endif // CAMERA_CLASS_HPP

// in the CPP

camera_class& get_camera()
{
   static camera_class the_camera;
   return the_camera;
}

这使您能够在不依赖camera_class的情况下使用单个extern实例,但同时不会强制您将其用作单身,因为代码的其他区域也可以自由创建自己的私有实例。

这可以实现为static的(自由函数)或camera_class成员函数。根据Scott Meyers的一些出色建议,我选择了前者:

  

如果您正在编写一个可以实现为a的函数   成员或作为非朋友的非成员,您应该更愿意实施   它作为非会员职能。

来源:http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197

答案 3 :(得分:2)

由于您要从多个文件中包含此文件,因此您违反了One Definition Rule

  

在整个程序中,对象或非内联函数不能有   不止一个定义

您应该将glcam定义放在源文件中,而不是放在头文件中,或者将其声明为extern,并在某个源文件中提供定义。

答案 4 :(得分:1)

include guard会阻止标题中的多个文本实例出现在一个编译单元中(即您构建的单个.cpp内置到.o中)

它不会阻止该文本的多个实例出现在多个编译单元中。

因此,在链接时,包含此标头的每个编译单元都有一个

 camera_class glcam = camera_class();

作为一种象征。 C ++无法决定何时引用“glcam”这个单一的全局定义。来自main.o的那个或来自camera_class.o的那个?

答案 5 :(得分:0)

它工作得很好,你只在每个源文件中得到一个定义。

问题是您有多个源文件,链接器正在查找多个定义。

在头文件中,您应该输入:

extern camera_class glcam;

然后在一个且只有一个源文件中放置您曾经拥有的标题:

camera_class glcam = camera_class();

此时您需要了解初始化顺序问题。不要试图从任何静态对象中使用glcam