C++包括警卫似乎不起作用?
C++ include guard doesn't appear to work?
我以前多次使用include保护,但从未真正了解它们的工作方式或原因。
为什么以下不起作用?
#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
另外,有人能向我解释一下为什么头球后卫能起作用吗?
标头保护将防止在单个翻译单元中包含多个内容。标题可以(现在)包含在多个翻译单元中:
// a.cpp:
#include "camera.hpp"
// b.cpp
#include "camera.hpp"
这将产生a.obj
和b.obj
,每个都包含glcam
的定义。当链接在一起生成最终的二进制文件时,会出现多重定义错误。
您需要在标头中声明glcam
,并在.cpp
文件中定义一次:
// camera.hpp
...
extern camera_class glcam;
// camera.cpp
#include "camera.hpp"
camera_class glcam;
根本原因:
标头保护可防止在同一翻译单元中多次包含同一标头,但不能跨不同的翻译单元。如果在多个翻译单元中包含相同的头文件,则glcam
的副本实际上是在每个包含标题的翻译单元中创建的
C++标准要求每个符号只能被定义一次(一个定义规则),因此链接器会向您发出错误。
解决方案:
不要在头文件中创建glcam
。相反,它应该以这样一种方式创建,即只定义一次。正确的方法是使用关键字extern
。
看起来您想要创建一个可以在多个地方使用的单个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;
}
这使您能够在不依赖extern
的情况下使用单个camera_class
实例,但同时不会强制您将其作为单例使用,因为代码的其他区域也可以自由创建自己的私有实例。
这可以按原样(自由函数)或作为camera_class
的static
成员函数来实现。根据Scott Meyers的一些优秀建议,我选择了前者:
如果您正在编写一个函数,该函数可以实现为成员或作为非朋友非成员,您应该更愿意实现它是一个非成员函数。
来源:http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197
由于您从多个文件中包含此文件,因此您违反了一个定义规则:
在整个程序中,对象或非内联函数不能具有多个定义
应该将glcam
定义放在源文件中,而不是放在头文件中,或者将其声明为extern
,并在某个源文件中提供定义。
include保护防止标头中文本的多个实例出现在一个编译单元中(即您正在构建的单个.cpp,它被构建到.o中)
它不会阻止该文本的多个实例出现在多个编译单元中。
因此,在链接时,包含此标头的每个编译单元都有一个
camera_class glcam = camera_class();
作为一个象征。当提到"glcam"时,C++无法决定你指的是哪一个全局定义。来自main.o的还是来自camera_class.o的?
它运行得很好,在每个源文件中只得到一个定义。
问题是您有多个源文件,而链接器正在查找多个定义。
在头文件中,您应该放:
extern camera_class glcam;
然后在一个也是唯一一个源文件中,将您过去拥有的内容放在标题中:
camera_class glcam = camera_class();
此时,您需要注意初始化顺序问题。不要试图从任何静态对象中使用glcam
。
- 我的神经网络不起作用 [XOR 问题]
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- C++为什么尽管我调用了void函数,它却不起作用
- 为什么在保护模式下继承升级不起作用
- 循环在计数器中不起作用
- 在其他文件中创建类时在 c++ 项目中不起作用
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- 为什么二进制搜索在我的测试中不起作用
- 我的代码中有错误吗?使用BGI图形的C++代码对我不起作用
- 为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?
- 带有指定长度字符* 参数的 std::regex_search 在 VS2017 中不起作用?
- Bjarne Stroustrup Book - std_lib_facilities.h - 不起作用(未知类型名称)
- 为什么简单的算术减法在"if"条件下不起作用?
- 为什么Stroustup书中的has_f不起作用
- 包括在 <sstream> Xcode 9.2 中不起作用
- 包括不起作用C 的文件
- 包括不起作用的警卫
- C++包括警卫似乎不起作用?
- PCL 包括卷积不起作用