昨天,嘗試一個項目,遇到了如下的問題。先來還原一下:
頭文件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時,將在鏈接時導致符號重定義錯誤。要避免這種情況,需要去除全局對象,將全局函數封裝為類的靜態方法。或者聲明與定義分開。