第六十五篇:VS工程文件中cpp、h文件在main中调用关系及如何避免出现“找到一个或多个多重定义的符号”

作者:liaojiacai    邮箱: ljc_v2x_adas@foxmail.com

1、出现的问题:”error   LNK1169:   找到一个或多个多重定义的符号“的错误

2、该问题出现的场景:(假设有一个A.h,A.cpp,main,在main中调用了A.cpp文件中的函数,A.cpp文件中的部分变量是在A.h文件中声明的)

有多个cpp文件和与之对应的h文件,在main中调用这些文件时候需要包含进去,cpp文件中有包含h文件,main函数中也有h文件,当h文件中有定义的共有类时会出现这个问题,就是编译的时候出现重定义,之所以出现这个问题,是因为凡是包含h头文件的地方,都会执行一遍h文件里面的内容,cpp文件和main中都包含h文件,都会编译,这样谁先编译,那么等到编译另外一个文件的时候,h文件里面的东西都有了,再编译就会检查出重定义了,但是不包含h文件,那么h文件对应的cpp文件中的函数不能直接在main中使用,必须加extern,cpp文件不包含h文件,那么h文件中的部分变量没办法在cpp文件中定义

3、解决方法:

重定义主要是头文件重复包含反复编译了

最直接的解决方法就是:

以head.h文件为例,head.h文件在head.cpp和main.cpp头文件中都包含了这样重复编译就会出错,解决方法如下: 

在有包含用到head.h的文件中最前面添加

#if !define(HEAD_H)
        #define HEAD_H

其实就是C++编程的基础知识,当然对没有系统学习过C++的,肯定是一脸懵逼!!!

智慧的网友给出了很多的解决方法,也放在下面:

方法1、参见博客

http://www.cnblogs.com/A-Song/archive/2012/03/23/2413782.html

这是基本的解决方法,就是把h文件中只放cpp文件中函数的声明,h中定义的变量都放在cpp文件的开头,cpp文件中不用包含h头文件,main中包含h头文件就OK了!!!

方法2、可以在VS里面设置强制编译

忽略这个问题这个方法也可行但是感觉很别扭,隐隐约约感觉到有问题,即使出了结果,感觉总有点不舒服,这种方法就是默认这里找到的同名的函数是一个,即两次编译的h文件是一个,忽略后面编译的一次

方法3、(其实不是方法,这是c++的标准规范的调用)

上面的两种办法的根本是没有搞清楚编译的过程,说白了就是没有搞清楚h文件,cpp文件,main文件之间的相互依赖关系,方法1会出现这样的问题,当我在h文件中声明的函数的参数中有在cpp文件中定义的类的时候,这种方法无解,因为方法1讲cpp文件需要的定义都放在cpp文件开始部分,h文件中声明的函数的参数又有cpp文件中定义的类,这样等等话,h文件中对函数申明失败,找不到使用了在cpp文件中定义的参数。如果在cpp文件和h文件中都声明了同一个类,这样h文件中声明带有这个类的参数的函数时候不会出现问题,但是h文件和cpp文件中都定义了同一个类,这明显重定义了。

正确的使用方法是:

下面举例子

1)main里面:

#include"Feature_Triangulate_3D_rebuild3.h"

2)Feature_Triangulate_3D_rebuild3.cpp里面:

#include"Feature_Triangulate_3D_rebuild3.h"

3)Feature_Triangulate_3D_rebuild3.h里面

#include"common.h"

bool TestTriangulation(const vector<CloudPoint>& pcloud, const Matx34d& P, vector<uchar>& status);

4)common.h里面

struct CloudPoint {
cv::Point3d pt;
std::vector<int> imgpt_for_img;
double reprojection_error;
};

std::vector<cv::Point3d> CloudPointsToPoints(const std::vector<CloudPoint> cpts);

5)common.cpp里面

#include"common.h"

std::vector<cv::Point3d> CloudPointsToPoints(const std::vector<CloudPoint> cpts)
{
std::vector<cv::Point3d> out;
for (unsigned int i = 0; i<cpts.size(); i++)
{
out.push_back(cpts[i].pt);
}
return out;
}

对上面说明main里面使用了Feature_Triangulate_3D_rebuild3.cpp文件中的TestTriangulation函数,TestTriangulation函数一个参数const vector<CloudPoint>& pcloud是自己定义的类,放在common.h里面,TestTriangulation函数里面调用了一个函数CloudPointsToPoints(const std::vector<CloudPoint> cpts),这个函数放在common.cpp文件中

编译说明:

从main开始,遇到#include"Feature_Triangulate_3D_rebuild3.h“时进入include"Feature_Triangulate_3D_rebuild3.h中,又遇到#include"common.h",把common.h里面的CloudPoint类申明了,把CloudPointsToPoints函数也申明了(申明的时候就是告诉到common.cpp里面去找这个CloudPointsToPoints这个函数),common.h里面编译完,回到nclude"Feature_Triangulate_3D_rebuild3.h中,执行#include"common.h"后面的bool TestTriangulation(const vector<CloudPoint>& pcloud, const Matx34d& P, vector<uchar>& status)函数申明,这个函数会遇到 有参数CloudPoint类和CloudPointsToPoints函数,这两个都在前面申明了,所以编译不会出现问题。所以mian函数里面的#include"Feature_Triangulate_3D_rebuild3.h"执行完毕,就把我们使用TestTriangulation函数要用到的东西全都搞定了。所有的cpp文件都通过h头文件调用编译成功。



  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值