1>OpenCVFi.obj : error LNK2005: "class cv::Point_<double> __cdecl reverse(class cv::Point_<double> const &)" (?reverse@@YA?AV?$Point_@N@cv@@ABV12@@Z) 已经在 HalconFi.obj 中定义
背景:
项目架构为,主程序A,dll库B,dll库中引用了另外一个dll库C,BC都引用了openCV库,单独编译为添加引用c的b没问题,编译c也测试正常,将c添加到b后编译出错,报错如题所示。
查询发现问题原因应该是这个:https://blog.csdn.net/zhaoyong26/article/details/84635383
但是用了网上的#pragma once,#ifndef,extern都没能解决
经过仔细看代码发现,我的情况是这样的一个全局变量在一个头文件中定义,比如:C.h中定义了全局变量int a = 10;
在一个类的头文件B.h中引用头文件C.h如:include "C.h"
此时就会报题目中的错误。
解决办法:
将include "C.h"从B.h中移到了B.cpp中.
分析:
头文件中不可以放变量的定义!!!一般情况下头文件中只放变量的声明,因为头文件要被其他文件包含(即#include),如果把定义放到头文件的话,就不能避免多次定义变量,C++不允许多次定义变量,一个程序中对指定变量的定义只有一次,声明可以无数次。
注意头文件中不可以放变量的定义!!!一般情况下头文件中只放变量的声明,因为头文件要被其他文件包含(即#include),如果把定义放到头文件的话,就不能避免多次定义变量,C++不允许多次定义变量,一个程序中对指定变量的定义只有一次,声明可以无数次。
不过有三个例外,以下三种实体的定义也可放到头文件中。
1.值在编译时就已知的const 变量的定义可以放到头文件中
如:const int num(10);
2.类的定义可以放到头文件中
3.inline 函数
这三个实体可以定义在多个源文件中,只要在每个源文件中的定义相同。
只要两个或者以上的.cpp同时包含了一个定义了变量的.h文件,就会提示错误.
不过注意, 这中间可能会包含些比较复杂的逻辑关系..
例如我的那坨代码..
假定一个定义了变量的1.h文件
有1.cpp和2.cpp, 1.cpp包含1.h, 2.cpp只包含2.h 但是2.h包含了1.h.. 所以1.h中定义的变量编译的时候会在2.pp中有定义. 于是乎2.cpp翻译成的obj里也会有定义, 结果导致提示obj里重定义.
在头文件和cpp文件错中复杂的情况下, 根本就很难判断其祸根源.
所以得出结论:
没事就别在.h中定义变量,或者初始化静态成员变量(我就是后一种情况).
参考文献:
https://blog.csdn.net/zhaoyong26/article/details/84635383
https://blog.csdn.net/jiangge123456/article/details/20865371
另外整理一个完整的,调整了原版格式,贴在下面,大家一起探讨~
出现上面的错误,只要原因有如下几个:
1.头文件的重复包含
包含的头文件中含有变量、函数、类的定义,在其他使用的地方多次包含,造成重复包含,产生LNK2005错误,
有两种解决方法:
1)使用宏 在头文件head.h中加入
#ifndef HEAD_H_ //这个地方写法有不少 #define HEAD_H_ ...... #endif
2)使用预编译,文件开头加入
#pragma once
2. 使用第三方库造成
主要情形是C运行期函数库和MFC的库冲突造成的。具体的方法就是将提示出错的库放到另一个库的前面。
举例:
#include <WinSock2.h> //WinSock2.h头文件必须在Windows.h之前 #include <Windows.h>
3. 重复定义全局变量
全局变量是针对整个工程的,在一个CPP文件的定义:int nCount;那么在使用的CPP文件中就应该使用extern int nCount即可,如果还是使用int nCount 就会产生LNK2005错误;
根据C++标准的规定,一个变量是声明,必须同时满足两个条件,否则就是定义:
1)使用extern 关键字 2)不能给变量赋初值
如果还是报错的话,只在头文件中声明函数,把函数定义都放到cpp文件中。这里面转自https://blog.csdn.net/wanzew/article/details/81638128出现的问题:
这里我有三个源文件:Base.hpp, Base.cpp 和 main.cpp
在Base.hpp里面定义一个基类,注意,基类只包含构造函数和析构函数的声明,函数在Base.cpp里实现。
此外在Base.hpp中还有一个函数的定义(函数声明和定义都在Base.hpp文件中)三个文件代码如下:
// Base.hpp #ifndef VIRTUAL_H #define VIRTUAL_H #include<iostream> #include<string> using namespace std; class Base{ public: Base(); ~Base(); private: char *p; }; void platform(Base *pBase){ cout << "this is just a function..." << endl; } #endif //Base.cpp #include"Base.hpp" Base::Base(){ cout << "construction function..." << endl; } Base::~Base(){ cout << "destructor function..." << endl; delete p; } //main.cpp #include"Base.hpp" #include<iostream> using namespace std; int main(){ cout << "main..." << endl; Base * pBase = new Base; delete pBase; system("pause"); return 0; }
此时编译会出现一个问题:1>Base.obj : error LNK2005: "void __cdecl platform(class Base *)" (?platform@@YAXPAVBase@@@Z) 已经在 main.obj 中定义
1>c:\users\wanzew\documents\visual studio 2013\Projects\Class\Debug\Class.exe : fatal error LNK1169: 找到一个或多个多重定义的符号
经过分析,确定了这是由于两个实现文件(main.cpp 和 base.cpp)中重复包含了头文件#include<base.hpp>而造成的。
要注意的是,在这里,在头文件中加入#ifndef……#endif这样的预编译命令是没用的,因为这是防止嵌套包含头文件的,而本例中并没有嵌套包含,是 在两个文件中分别包含。只在头文件中声明函数,把函数定义都放到cpp文件中,本例中把platform函数的定义从Base.hpp文件中移到Base.cpp文件中。
————————————————
版权声明:本文为CSDN博主「Wzning0421」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hanzhen7541/article/details/99681461
其他人的解决方案:
Let's detail a bit:
testDoc.h includes mytest.h
testDoc.h is included by testDoc.cpp and testView.cpp
So once the function bp5 will be compiled in testDoc.obj and once in testView.obj. The #pragma once prevents the header file to be included many times in the same .cpp file not in different cpp files.
You have 2 solutions for this:
1. make the function inline:
inline void bp5() {
int a = 0;
a += 1;
}
2.
put the function in a cpp file and in the header add only:
void bp5();
var code = "bd9610e7-2f2a-4dd0-ab70-a414052825b5"