昨天,尝试一个项目,遇到了如下的问题。先来还原一下:
头文件test.h
#pragma once
#include <Eigen/Core>
#include <iostream>using namespace Eigen;
using namespace std;class point2
{
public:
point2(int x1,int y1):x(x1),y(y1){}
point2& operator+(point2 s);private:
int x,y;
};class DirectEllipseFit
{
public:DirectEllipseFit(const Eigen::VectorXd &xData, const Eigen::VectorXd &yData);
private:
Eigen::VectorXd m_xData;
Eigen::VectorXd m_yData;};DirectEllipseFit::DirectEllipseFit( const Eigen::VectorXd &xData, const Eigen::VectorXd &yData)
{
m_xData = xData;
m_yData = yData;
}
test.cpp
#include"test.h"point2& point2::operator+(point2 s)
{this->x=x+s.x;this->y+=s.y;return *this;
}
main.cpp
#include "test.h"int main(void)
{return 0;
}
结果程序链接阶段,出现如下错误:
1>test.obj : error LNK2005: "public: __thiscall DirectEllipseFit::DirectEllipseFit(class Eigen::Matrix<double,-1,1,0,-1,1> const &,class Eigen::Matrix<double,-1,1,0,-1,1> const &)" (??0DirectEllipseFit@@QAE@ABV?$Matrix@N$0?0$00$0A@$0?0$00@Eigen@@0@Z) 已经在 main.obj 中定义
1>E:\c++\testEigen\Debug\testEigen.exe : fatal error LNK1169: 找到一个或多个多重定义的符号
开始百思不得其解,后来想到了定义类时,一般声明和实现分离,于是我将DirectEllipseFit的构造函数移到了test.cpp中,果然问题解决了。后来查看资料,终于找到了原因。
实际上,test.cpp由于包含了test.h,而test.h中包含了构造函数的实现,于是test.cpp生成目标文件的时候,包含了构造函数的实现。而main.cpp也包含了test.h,同样编译生成目标文件的时候,也会包含构造函数的实现。这样二者在链接阶段就会发现有两个一模一样的函数,出现了重定义的问题。
解决这个问题的方法,有两种:
一、添加inline关键字,这样实际上是在调用处展开函数体代码,代替函数调用。
即:
class DirectEllipseFit
{
public:inline DirectEllipseFit(const Eigen::VectorXd &xData, const Eigen::VectorXd &yData);
private:Eigen::VectorXd m_xData;Eigen::VectorXd m_yData;};DirectEllipseFit::DirectEllipseFit( const Eigen::VectorXd &xData, const Eigen::VectorXd &yData)
{m_xData = xData;m_yData = yData;
}
二、将函数实现放在test.cpp中,这样就不会出现重定义问题。
PS:
其实还有一种情况也会出现以上问题,即如果我们在test.h中定义一个全局变量,也会出现这个问题,具体可参考:
《 C++杂记:“error LNK1169: 找到一个或多个多重定义的符号”的解决方法》
《HPP定义也会出现这个问题》:由于hpp本质上是作为.h被调用者include,所以当hpp文件中存在全局对象或者全局函数,而该hpp被多个调用者include时,将在链接时导致符号重定义错误。要避免这种情况,需要去除全局对象,将全局函数封装为类的静态方法。或者声明与定义分开。