奇怪的重新定义符号

时间:2010-04-21 06:28:23

标签: c++ include compiler-errors

我将此标题包含在我自己的标题中:http://codepad.org/lgJ6KM6b
当我编译时,我开始收到这样的错误:

CMakeFiles/bin.dir/SoundProjection.cc.o: In function `Gnuplot::reset_plot()':
/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/include/g++-v4/new:105: multiple definition of `Gnuplot::reset_plot()'
CMakeFiles/bin.dir/main.cc.o:project/gnuplot-cpp/gnuplot_i.hpp:962: first defined here
CMakeFiles/bin.dir/SoundProjection.cc.o: In function `Gnuplot::set_smooth(std::basic_string, std::allocator > const&)':
project/gnuplot-cpp/gnuplot_i.hpp:1041: multiple definition of `Gnuplot::set_smooth(std::basic_string, std::allocator > const&)'
CMakeFiles/bin.dir/main.cc.o:project/gnuplot-cpp/gnuplot_i.hpp:1041: first defined here
CMakeFiles/bin.dir/SoundProjection.cc.o:/usr/include/eigen2/Eigen/src/Core/arch/SSE/PacketMath.h:41: multiple definition of `Gnuplot::m_sGNUPlotFileName'

我知道在这个烂摊子里很难看到,但看看重新定义发生的地方。它们发生在/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/include/g++-v4/new:105等文件中。新运算符如何获取有关gnuplot标头的信息?我甚至无法编辑该文件。怎么可能这样呢?我甚至不确定如何开始调试这个。我希望我已经提供了足够的信息。我无法在一个小项目中重现这一点。我主要只是寻找有关如何找出这种情况的原因以及如何追踪它的提示。

感谢。

3 个答案:

答案 0 :(得分:3)

你显然违反了“一个定义规则”。您的头文件中有很多定义。其中一些是类或类模板(很好),其中一些是内联函数或函数模板(也很好),其中一些是“普通”函数和非模板的静态成员(这不是很好) )。

class foo;       // declaration of foo
class foo {      // definition of foo
   static int x; // declaration of foo::x
};

int foo::x;      // definition of foo::x

void bar();      // declaration
void bar() {}    // definition

一个定义规则表明您的程序最多只能包含一个实体的定义。例外是类,内联函数,函数模板,类模板的静态成员(我可能忘记了一些东西)。对于那些实体,只要同一实体的两个定义不在同一翻译单元中,就可以存在多个定义。因此,将此头文件包含到多个翻译单元中会导致多个定义。

答案 1 :(得分:1)

看起来您包含了冲突的标头。尝试检查您的包含路径。它们通常在-I指令(至少在gcc中)或环境变量中定义。

答案 2 :(得分:0)

读取编译器错误通常会有所帮助。您应该学会理解编译器告诉您的内容。它抱怨重新定义符号的事实是说你违反了一个定义规则。然后它甚至会告诉你符号是什么:

class GnuPlot {
//...
   GnuPlot& reset_plot(); // <-- declaration
//...
};
//...
Gnuplot& Gnuplot::reset_plot() { // <-- Definition
    nplots = 0;
    return *this;
}

您可以在程序中多次声明符号,但只能定义一次(除非它是内联的)。在这种情况下,reset_plot在包含标题的所有翻译单元中进行编译和定义,违反了一个定义规则。

最简单的方法是将其声明为内联,以便它可以出现在多个编译单元中,并让链接器稍后删除冗余副本(如果有的话)。

更有问题的是必须在类中声明并在转换单元中定义(仅一次)的静态成员。为此,您可以创建一个.cpp文件来定义这些变量(以及您不需要在标题中内联的任何函数/方法)。