问题描述
我正在学习C ++,并且遇到(并修复)了一个看起来很经典的问题:
g++ main.cpp A.cpp B.cpp -o out
In file included from B.h:1,from main.cpp:3:
A.h:1:7: error: redefinition of ‘class A’
1 | class A {
| ^
In file included from main.cpp:2:
经过快速研究(假设我理解正确),发生的原因是#include operation is not "idempotent"(我发现此问题的一个术语)。
为说明我的问题,我提出了一个最小的工作示例。
main.cpp
#include "A.h" #include "B.h" #include <iostream> int main () { std::cout << "Hello world" << std::endl; A a; B b(a); return 0; }
A.h
#include <iostream> class A { public: void test(); };
A.cpp
#include "A.h" void A::test () { std::cout << "test" << std::endl; }
B.h
#include "A.h" class B { public: B(A); };
B.cpp
#include "B.h" #include <iostream> B::B(A a){ a.test(); }
使用g++ main.cpp A.cpp B.cpp
或更具体地说g++ -c main.cpp
编译程序将失败,并显示上面的错误。
我了解到,编译器transcludes在编译main.cpp时会两次“ A”的标头(一次在main.cpp:1处,一次在Bh:1期间,在main.cpp:2中包含一次)。实际上,编译器两次“看到” class A
的定义,并认为我们两次定义了A。
我无法理解的是包含防护:
要解决此问题,可以在包含多个文件的文件顶部使用关键字pragma once
:
一次用#pragma修复的A.h
#pragma once #include <iostream> class A { public: void test(); };
允许程序很好地编译。
对我来说,这意味着我应该以#pragma开始每个标题一次!哪个不对?这是惯例吗?如果是这样,有没有办法在编译时执行此操作(例如,作为标志)?
如果我不这样做,那么我不能将对象A用作类A的成员,也不能将其作为参数传递给B(例如在我的示例中B的构造函数中),如果这样的A和B可以在另一个文件中单独使用;除非我每次出现问题时都反应性地添加#pragma once
,这对我来说似乎是“肮脏的”。此外,我担心无法在没有自己添加文件中添加pragma once
的情况下与任何人共享我的源代码,而担心他们遇到了我的两个对象。
我想念什么?有办法完全避免这个问题吗?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)