所以我有一个旨在从文件中读取的函数。它在FileIO.h中声明和定义,如下所示:
std::string ReadFromFile(std::ifstream& in)
{
std::string out;
in >> out;
return out;
}
现在,我将此标题包含在另一个标题中,该标题本身包含在另一个标题中,该标题包含在main中。即使它没有被包含在多个内容中,但我在所有头文件上都有#ifndef-#def-#endif
预处理器,并且具有唯一的名称。
我无法为我的生活弄清楚为什么它仍然抛出链接器错误(事实上,它抛出了两次:一次在我的Main中,一次在第二个头文件中)。然后我尝试在FileIO.h中声明函数,如下所示:
std::string ReadFromFile(std::ifstream& in);
然后我在FileIO.cpp中定义了它。没有更多链接器错误!这是因为我在函数中定义了变量,并且它们正在编译,然后在后面看到(例如std::string out
),还是来自其他东西?我很喜欢这个有效的原因。谢谢!
答案 0 :(得分:5)
你可能对你的包含警卫看起来不起作用感到困惑。这是这个难题的缺失部分:
编译器根据各个翻译单元处理您的代码。这只是“一个.cpp文件和它直接或间接包含的标题集”的一个奇特术语 - 重要的是每个TU都是独立于其他所有TU编译的。
当编译器处理时,例如main.cpp
它最终会看到您的标题,并在生成的ReadFromFile
中包含已编译的main.obj
。如果这是您项目中唯一的TU,那么在您实施ReadFromFile
的具体位置上没有任何区别。
但是如果你有另一个TU,例如stuff.cpp
也最终会引入定义ReadFromFile
的标题然后你就会遇到问题:该函数最终出现在main.obj
和stuff.obj
中,这会让链接器抱怨,因为现在你最终违反了One Definition Rule。
请注意,在每个单独的TU中,您的包含警卫按预期工作:无论您尝试拉入相同的标头多少次,编译器在处理每个包时都不会抱怨。
答案 1 :(得分:0)
您遇到链接器错误,因为在多个目标文件中实现了相同的功能,因为它是在头文件中实现的。
你可以通过在函数前使用static inline
来避免它。