ROS中不同文件之间的引用小结

在比较大的一些程序中,往往会涉及到一些不同模块的调用,如果这些东西放在一个.cpp文件内,这个文件会变的特别长,因此会使用多个文件互相引用。那么如何在ROS下进行这种不同文件下的引用呢,根据最近所学,简单记录一份笔记。

1、头文件的引用

头文件的引用可以说是最常见的,很多时候都会用到,举个简单的例子:

在multiple_file_test/include/multiple_file_test/test1目录下建立一个.h文件名为file1.h:


#ifndef FILE1_H_
#define FILE1_H_#include <memory>
namespace multiple_file_test {
namespace file1 {
class Test1 {public://1、关键字 explicit 用于声明构造函数,以防止隐式类型转换和复制(或赋值)构造函数的自动创建。//错误方式:MyClass myObject = 10; // 错误:不允许隐式转换//正确方式:MyClass myObject(10); // 正确//2、禁用复制构造函数和赋值操作符:在 Test1 类的示例中,复制构造函数和赋值操作符被删除(使用 = delete),这意味着编译器不会为这个类自动生成默认的复制构造函数和赋值操作符。explicit Test1();~Test1();Test1(const Test1 &) = delete;Test1 &operator=(const Test1 &) = delete;private:
};
int function1(){return 123;
}
}
}#endif

上述代码是一个最简单的头文件形式,它定义了一个namespace以及一个函数function1,这个函数会返回一个int型的数字123。

然后,在src目录下,建立一个main函数调用这个函数:

#include "ros/ros.h"#include "multiple_file_test/test1/file1.h"
namespace multiple_file_test {
namespace {void Run() {auto value = multiple_file_test::file1::function1();ROS_INFO("debug");std::cout<<"value:"<<value<<std::endl;
}
}
}int main(int argc, char **argv)
{ros::init(argc, argv, "multiple_file_test");ROS_INFO("multiple_file_test_node start");multiple_file_test::Run();return 0;
}

这里首先引入了头文件file1.h,然后在工作空间内调用了这个头文件下的具体函数function1,并打印最终结果。接下来编译这个头文件,在cmakelist中添加以下内容:

add_executable(main src/main.cpp)
add_dependencies(main ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})  
target_link_libraries(main ${CERES_LIBRARIES} ${catkin_LIBRARIES}) 

然后编译

然后

报错了:

fatal error: multiple_file_test/test1/file1.h: 没有那个文件或目录3 | #include "multiple_file_test/test1/file1.h"|          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

上面确实是有这个文件的,但是编译的时候没有找到,所以这时候需要在cmakelist中添加头文件所在路径:

include_directories(${PROJECT_SOURCE_DIR}/include${catkin_INCLUDE_DIRS}
)

重新编译后就可以执行了,然后运行可以得到如下结果:
在这里插入图片描述通过这种方式,可以实现在一个main函数中引用同一文件夹下的其他头文件了。

2、.cc函数的引用

除了引用某些头文件中的函数外,更多时候还需要引用其他.cc或者.cpp文件下的内容,举个例子,首先在multiple_file_test/include/multiple_file_test/test2目录下建立一个.h文件名为file2.h:


#ifndef FILE2_H_
#define FILE2_H_#include <memory>
namespace multiple_file_test {
namespace file2 {
class Test1 {public://1、关键字 explicit 用于声明构造函数,以防止隐式类型转换和复制(或赋值)构造函数的自动创建。//错误方式:MyClass myObject = 10; // 错误:不允许隐式转换//正确方式:MyClass myObject(10); // 正确//2、禁用复制构造函数和赋值操作符:在 MapBuilder 类的示例中,复制构造函数和赋值操作符被删除(使用 = delete),这意味着编译器不会为这个类自动生成默认的复制构造函数和赋值操作符。explicit Test1();~Test1();Test1(const Test1 &) = delete;Test1 &operator=(const Test1 &) = delete;private:};int function1();}
}#endif

这个代码本身与file1.h的代码基本是一致的,内容上的区别在于这里的函数function1只进行了声明但是没有函数实现。然后在同一目录下再建立一个.cc文件进行函数实现:

#include "multiple_file_test/test2/file2.h"
namespace multiple_file_test {
namespace file2 {int function1(){return 0;
}
}  
}  

这个文件补充了上面.h文件中的函数实现。同样再使用main函数调用这个函数:

#include "ros/ros.h"#include "multiple_file_test/test1/file1.h"
#include "multiple_file_test/test2/file2.h"
namespace multiple_file_test {
namespace {void Run() {auto value = multiple_file_test::file1::function1();ROS_INFO("debug");std::cout<<"value:"<<value<<std::endl;int value2 = multiple_file_test::file2::function1();ROS_INFO("debug");std::cout<<"value2:"<<value2<<std::endl;
}}
}int main(int argc, char **argv)
{ros::init(argc, argv, "multiple_file_test");ROS_INFO("multiple_file_test_node start");multiple_file_test::Run();return 0;
}

接下来进行编译,但是此时会报错:

CMakeFiles/main.dir/src/main.cpp.o: in function `multiple_file_test::(anonymous namespace)::Run()':
main.cpp:(.text+0x18e): undefined reference to `multiple_file_test::file2::function1()'
collect2: error: ld returned 1 exit status

这是由于主函数编译的时候只找到了头文件但是没有找到具体的函数实现。如果要找到函数实现,可以通过下述方式修改Cmakelist文件增加.cc的检索路径:

方式一、指定路径
在Cmakelist中给定确定路径,针对文件夹目录比较单一的情况下使用,例如:


file(GLOB MULTIPLE_FILE_SOURCES "include/multiple_file_test/test2/*.h" "include/multiple_file_test/test2/*.cc")
add_library(multiple_file_lib ${MULTIPLE_FILE_SOURCES})
add_executable(main src/main.cpp)
add_dependencies(main ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})  
target_link_libraries(main ${CERES_LIBRARIES} ${catkin_LIBRARIES} multiple_file_lib)

这个地方一共涉及了三个更改,首先是增加了file与add_library,然后是在target_link_libraries中添加了library。它的特点是file中路径必须是给定完整的,如果有多个目录的话写起来就会比较冗余。

方式二、检索路径
为了弥补上面的问题,可以采用路径检索的形式让其自动搜索。这里可以有两种不同的写法:

file(GLOB_RECURSE MULTIPLE_FILE_SOURCES"${CMAKE_SOURCE_DIR}/multiple_file_test/*.h""${CMAKE_SOURCE_DIR}/multiple_file_test/*.cc")

或者:

file(GLOB_RECURSE MULTIPLE_FILE_SOURCES"${CMAKE_CURRENT_SOURCE_DIR}/include/*.h""${CMAKE_CURRENT_SOURCE_DIR}/include/*.cc")

这两者的区别主要在于CMAKE_SOURCE_DIR与CMAKE_CURRENT_SOURCE_DIR。CMAKE_SOURCE_DIR与CMAKE_CURRENT_SOURCE_DIR是CMake 中两个非常重要的变量,它们定义了源代码树中的两个不同的目录,具体区别如下:

CMAKE_SOURCE_DIR:这个变量指向包含顶级 CMakeLists.txt 文件的目录。它是项目源代码的根目录,即你调用 cmake 命令的目录。无论在项目中的哪个 CMakeLists.txt 文件中,CMAKE_SOURCE_DIR 总是指向同一个目录。CMAKE_CURRENT_SOURCE_DIR:这个变量指向当前正在处理的 CMakeLists.txt 文件所在的目录。当你在项目的某个子目录中调用 cmake 或处理子目录中的 CMakeLists.txt 文件时,CMAKE_CURRENT_SOURCE_DIR 会根据当前文件的位置而变化。它是相对的,并且每个子目录中的 CMakeLists.txt 文件都会有不同的值。

简单来说,CMAKE_SOURCE_DIR 是项目的根目录,而 CMAKE_CURRENT_SOURCE_DIR 是当前正在被处理的目录。

举个例子:当你需要引用项目根目录下的文件或目录时,可以使用 CMAKE_SOURCE_DIR。例如,如果你的 CMakeLists.txt 位于 src/ 目录下,而你需要包含位于项目根目录下的 config/ 目录中的文件,你可以这样做:

include_directories(${CMAKE_SOURCE_DIR}/config)

而当你需要引用当前 CMakeLists.txt 所在目录下的文件或目录时,可以使用 CMAKE_CURRENT_SOURCE_DIR。例如,如果你正在 src/ 目录下的 CMakeLists.txt 中,并且需要包含相邻 include/ 目录中的文件,你可以这样做:

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)

后续的add_library,以及在target_link_libraries中添加了library这两项是一致的,通过这种方式,可以更加灵活的索引到需要的头文件。

然后编译运行一下,可以得到输出的结果为:
在这里插入图片描述
可以看到其调用了两个不同的工作空间下的函数并分别得到了不同的结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/43420.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tomcat 安装和优化

tomcatat tomcat和http一样&#xff0c;都是用来处理动态页面的 tomcat也可以作为web服务器&#xff0c;开源的 php.php tomcat.jsp nginx.html tomcat使用java代码写的程序&#xff0c;运行的是java的web服务程序 tomcat的特点和功能&#xff1a; 1、servlet容器&…

MySQL——第一次作业

部署MySQL 8.0环境 1&#xff0c;删除之前存在的MySQL程序 控制面板删除 2&#xff0c;删除完成后下载MySQL 官网&#xff1a; https://www.mysql.com 在window下下载MSI版本 3&#xff0c;自定义安装 4&#xff0c;配置环境变量 1&#xff0c;系统高级系统设置 2&#xff…

子序列问题

目录 最长递增子序列 摆动序列 最长递增子序列的个数 最长数对链 最长定差子序列 最长的斐波那契子序列的长度 最长等差数列 等差数列划分II-子序列 声明&#xff1a;接下来主要使用动态规划来解决问题&#xff01;&#xff01;&#xff01; 最长递增子序列 题目 思路…

如何通过文件分发系统,实现能源电力企业文件的安全分发流转?

随着企业业务的快速发展&#xff0c;能源电力企业会在全国乃至全球&#xff0c;设立总部-分部-办事处/网点等多层级的结构&#xff0c;因此会涉及自动化的文件分发的业务场景。文件分发系统是一种将文件从一个地方自动传输到多个接收者的过程&#xff0c;可以提高工作效率&…

香港优才计划多少分获批成功率高?一文看懂各分数段获批情况!

有留意香港优才计划的朋友&#xff0c;应该都了解过&#xff0c;申请优才计划采用打分制&#xff0c;得分多少与最终获批有密不可分的关系。但有一点要提前清楚&#xff0c;申请优才不是得分越高就一定能获批&#xff0c;也不是得分低就一定没希望。 香港优才计划能否获批成功…

正确理解驱动电流与驱动速度

本文主要阐述了在驱动芯片中表征驱动能力的关键参数&#xff1a;驱动电流和驱动时间的关系&#xff0c;并且通过实验解释了如何正确理解这些参数在实际应用中的表现。 驱动芯片概述 功率器件如MOSFET、IGBT需要驱动电路的配合从而得以正常地工作。图1显示了一个驱动芯片驱动一…

迅狐抖音机构号授权矩阵系统源码

在数字化营销的浪潮中&#xff0c;抖音以其独特的短视频形式迅速崛起&#xff0c;成为品牌传播和用户互动的重要平台。迅狐抖音机构号授权矩阵系统源码作为一项创新技术&#xff0c;为品牌在抖音上的深度运营提供了强大支持。 迅狐抖音机构号授权矩阵系统源码简介 迅狐抖音机…

新版Android Studio中设置gradle的JDK版本

旧版android studio 在旧版&#xff08;具体哪个版本号之前搞不清了&#xff09;中设置JDK版本在>File——>Project Structure——>SDK location——>Gradle Setting——>Gradle SDK 新版android studio 某次更新后发现SDK location下找不到Gradle Setting选项…

通过Vxlan实现数据中心互联有感

随着企业的发展&#xff0c;为满足跨地域运营、用户接入、异地灾备等场景&#xff0c;越来越多的企业通常在多地域部署多个数据中心。 数据中心互联DCl(Data Center Interconnection)是不同数据中心VM之间互相通信的一种解决方案使用VXLAN、BGP EVPN等技术&#xff0c;使数据中…

uniapp+uview实现手机端上传照片带水印(保姆级全过程)

目录 前言&#xff1a;实现思路 步骤一、在界面使用uview的u-upload组件、放置canvas标签 步骤二、在afterRead方法中获取照片url&#xff0c;并创建画布生成水印&#xff0c;再将生成水印的照片上传到服务器 1、afterRead方法 2、照片加水印的方法 3、上传照片至服务器 …

zookeeper加入开机启动项

Windows的任务计划程序&#xff08;Task Scheduler&#xff09;是一个强大的工具&#xff0c;允许你安排程序在特定时间自动运行&#xff0c;包括开机时。 打开任务计划程序&#xff1a; 按下Win R键&#xff0c;打开“运行”对话框。输入taskschd.msc并回车&#xff0c;打开…

Python编写网络嗅探器程序捕获和显示IP数据包的头部信息

Python编写网络嗅探器程序捕获和显示IP数据包的头部信息 抓取网络数据包并解析其中的IP首部信息&#xff0c;并通过GUI界面显示解析结果。程序展示了如何使用Python的socket和ctypes库来捕获和解析网络数据包,并使用Tkinter创建一个简单的GUI界面来显示捕获到的IP头部信息。这…

日志服务SLS入门指南

日志服务SLS入门指南 什么是日志服务SLSNginx日志采集部署Nginx创建Logstore接入数据 数据脱敏创建脱敏Logstore数据加工 告警设置添加告警规则查看告警 写在最后 什么是日志服务SLS 在说到日志服务SLS之前&#xff0c;首先了解一下什么是日志服务SLS&#xff1f;日志服务SLS是…

PHP项目中的前端页面随意点击卡片后会重定向到首页或登录页

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

pycharm使用micropython

一、打开设置 2、搜索micropython、安装、重启 3、第5步需要设置成你插的电脑USB口&#xff0c;一个一个试 4、 5、 6、OK

手机数据恢复篇:优秀的 iPhone 数据恢复汇总

如果您不幸遭遇 iPhone 死机、进水或死机&#xff0c;一切还不算晚。您可以使用 iPhone 数据恢复应用恢复文件、照片、应用数据、消息等。 使用以下选项&#xff0c;您可以恢复 iPhone 上的少量内容、特定项目或所有内容。有些应用程序甚至提供修复工具来修复最初导致数据丢失…

这组杭州亚运会可视化大屏,绝对引领了时代。

本期分享杭州亚运会的可视化大屏&#xff0c;非常的震撼&#xff0c;杭州不愧为我国互联网最发达的的城市之一。 怒赞&#xff01;&#xff01;&#xff01;

暑期旅游怎么玩?开发旅游小程序让出行变简单

暑假正值旅游旺季&#xff0c;旅游小程序的出现为旅行带来了许多便利。随着移动互联网的发展&#xff0c;旅游行业也在不断寻求创新与变革。旅游小程序为游客提供了更加便捷的旅行体验&#xff0c;通过旅游小程序&#xff0c;用户可以了解旅游信息、旅游服务、在线咨询等&#…

【Dison夏令营 Day 13】使用 Python 创建扫雷游戏

在本文中&#xff0c;我们将介绍如何使用 Python 语言创建自己的基于终端的扫雷程序。 关于游戏 1992年4月6日&#xff0c;扫雷和纸牌、空当接龙等小游戏搭载在Windows 3.1系统中与用户见面&#xff0c;主要目的是让用户训练使用鼠标。扫雷是一款单人游戏&#xff0c;这个游戏…

Linux系统下anaconda的安装与Pytorch环境的下载

首先&#xff0c;在命令行通过cd命令&#xff0c;进入用户文件夹 cd xxx/xxx/username进入anaconda官网https://repo.anaconda.com/archive/&#xff0c;寻找anaconda下载包资源&#xff0c;这里选择最新的anaconda下载包 Anaconda3-2024.06-1-Linux-x86_64.sh 在命令行执行安…