提问cpp之编译单元

提问cpp之编译单元

  • 提问1:
  • 回答1:
    • 为什么模板都写在头文件里,写在.cpp文件会怎样?
    • 头文件中直接定义int a会有什么问题?
    • 为什么重复定义会出问题,这是谁判断的?
  • 提问2:
  • 回答2:
  • 错误再现(动图)

提问1:

问,为什么模板都写h头文件里面,非要写cpp文件会咋样?还有什么头文件直接int a会有啥问题,我说可能会重复定义,然后问我为啥重复定义就会出问题,这块是谁判断的?

回答1:

你提到的两个问题涉及到C++模板的使用习惯以及C/C++中全局变量定义的问题,下面我分别解释一下:

为什么模板都写在头文件里,写在.cpp文件会怎样?

C++模板是一种编程技术,允许程序员编写与类型无关的代码。当你使用模板定义一个函数或类时,编译器会根据你实际使用的类型生成具体的实现。这个过程叫做模板实例化。

  • 写在头文件(.h或.hpp)中:将模板定义在头文件中,意味着当这个头文件被包含到一个.cpp文件中时,模板的定义也被一起包含进来。这样,编译器在编译这个.cpp文件时,就可以看到模板定义并据此生成相应类型的实例化代码。这是必要的,因为C++标准规定,模板的实例化是在编译时进行的,而且必须在调用模板代码之前或者在模板定义所在的编译单元中完成。
  • 写在.cpp文件中:如果你把模板的定义只放在一个.cpp文件中,那么其他.cpp文件中的代码如果试图使用这个模板,编译器是看不到模板定义的,因为编译器是分别编译每个.cpp文件的。结果就是,编译器无法为这些外部使用的类型生成模板的实例,导致链接错误,因为在链接阶段,链接器找不到模板实例的具体实现。

头文件中直接定义int a会有什么问题?

在头文件中直接定义全局变量(如int a;)会引起多重定义的问题。这是因为当多个.cpp文件包含同一个头文件时,每个.cpp文件都会有一个a的定义。当这些.cpp文件被编译成对象文件后,链接器在尝试将它们链接成一个可执行文件时,会发现有多个a的定义,这违反了C/C++中关于一个程序内全局标识符(如变量、函数等)应有且只有一个定义的规则(One Definition Rule, ODR)。

为了解决这个问题,通常在头文件中使用extern关键字来声明全局变量而不是定义它。如extern int a;,然后在某一个.cpp文件中定义这个变量int a;。这样,a的定义只存在于一个地方,而其他文件通过包含头文件来引用a的声明,从而避免了多重定义的问题。

为什么重复定义会出问题,这是谁判断的?

关于为什么重复定义会出问题,这是由编译器和链接器共同决定的。编译器负责处理单个源文件,确保语法和语义的正确性。当多个源文件编译后需要合并成一个程序时,这个任务就交给了链接器。链接器发现同一个符号有多个定义时,就会报错,因为它无法确定应该使用哪一个定义,这可能导致程序行为的不确定性。

简而言之,重复定义的问题主要在链接阶段被链接器发现并报错。这背后的原理是为了保证程序的一致性和预期行为,防止因为变量或函数的重复定义导致的潜在冲突和错误。

提问2:

只有一个cpp文件还行,不会保错,cpp文件≥2时,当你把模板声明在头文件,把模板定义到1.cpp时,编译时2.cpp如果用到了该模板,他就不知道了模板咋定义的了,每个cpp都是单独编译的

回答2:

你的理解是正确的。如果你将模板的声明放在头文件中,而将具体的定义放在某个.cpp文件中,那么当其他.cpp文件通过包含那个头文件试图使用该模板时,会遇到问题。因为模板的具体实现(定义)对于这些其他的.cpp文件来说是不可见的,编译器在编译这些其他文件时不能实例化所需的模板,从而导致链接错误。
这是因为模板的实例化通常发生在编译期间,编译器需要看到模板的完整定义来生成针对特定类型的代码。当模板的定义仅存在于一个.cpp文件中时,其他.cpp文件中的代码尽管包含了模板的声明,但在编译时它们无法访问到模板定义,因此编译器无法生成这些模板的实例。
这也是为什么推荐将模板的定义放在头文件中,或者使用模板的显式实例化(explicit instantiation)和显式特化(explicit specialization)来避免这个问题的原因之一。通过在头文件中包含模板的完整定义,确保了每个包含该头文件的.cpp文件都能看到模板定义,从而允许编译器为需要的类型生成模板实例。
当然,如果你的项目只包含一个.cpp文件,这个问题就不存在了,因为模板的声明和定义都在同一个编译单元中,编译器能够找到并实例化所需的模板。所以,你完全理解了模板在多文件项目中的使用限制,以及为什么在实践中通常将模板定义放在头文件中的原因。

错误再现(动图)

待补充…

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

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

相关文章

featup入坑笔记

一、新建环境 在conda中建立一个虚拟环境featup, conda create -n featup python3.9 二、开始配置: 我是先下载了FeatUp,之后 pip install -e . -i https://mirrors.aliyun.com/pypi/simple/ 但是,突然出错了,说无法…

leetcode2529-正整数和负整数的最大计数

题目: 给你一个按 非递减顺序 排列的数组 nums ,返回正整数数目和负整数数目中的最大值。 换句话讲,如果 nums 中正整数的数目是 pos ,而负整数的数目是 neg ,返回 pos 和 neg二者中的最大值。 注意:0 既不是正整数…

MyBatis输出映射

1 resultType resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。如果返回的是集合,设置的是集合元素的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。 1.1 输出简单类型 案例&…

记Kubernetes(k8s):访问 Prometheus UI界面:Warning: Error fetching server time

记Kubernetes(k8s):访问 Prometheus UI界面:Warning: Error fetching server time 1、报错详情2、解决3、再次访问 PrometheusUI界面 💖The Begin💖点点关注,收藏不迷路💖 1、报错详情 Warning:…

软件杯 深度学习人体跌倒检测 -yolo 机器视觉 opencv python

0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于深度学习的人体跌倒检测算法研究与实现 ** 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🥇学长这里给一个题目综合评分(每项满…

MyBatis事务管理

MyBatis的事务管理是由TransactionFactory和Transaction两个接口定义的,TransactionFactory负责生成Transaction,这是一个典型的工厂模式。 官方提供了事务管理的两种模式: Managed:对应ManagedTransactionFactory和ManagedTran…

第四百四十一回 再谈flutter_native_splash包

文章目录 1. 知识回顾2. 使用方法3. 示例代码4. 经验与总结4.1 经验分享4.2 内容总结 我们在上一章回中介绍了"overlay_tooltip简介"相关的内容,本章回中将 再谈flutter_native_splash包.闲话休提,让我们一起Talk Flutter吧。 1. 知识回顾 我…

视频插针调研

视频插针 1、评估指标2、准确度3、实时4、视频流处理3、实时RIFE视频插帧测试 1、评估指标 参考:https://blog.csdn.net/weixin_43478836/article/details/104159648 https://blog.csdn.net/weixin_43605641/article/details/118088814 PSNR和SSIM PSNR数值越大表…

面试准备 集合 List

ArrayList 底层实现 使用Object[] 动态数组进行存储 特性 支持存储null值非线程安全支持快速访问 初始化方法 无参–返回一个空的列表(DEFAULTCAPACITY_EMPTY_ELEMENTDATA)指定初始容量: new ArrayList(20);指定集合 new ArrayList(col…

Opencv驱动摄像头

Opencv驱动摄像头&#xff0c;此段代码只能驱动电脑自带摄像头&#xff0c;目前没有分析出为何不能驱动另外连接的相机&#xff01; #include<iostream> #include<opencv2\core.hpp> #include<opencv2\highgui.hpp> #include<opencv2\imgproc.hpp> #i…

ubuntu下NTFS分区无法访问挂载-解决办法!

Ubuntu系统下&#xff0c;有的时候发现&#xff0c;挂载的NTFS文件系统硬盘无法访问。点击弹出类似问题&#xff1a; Error mounting /dev/sda1 at /media/root/新加卷: Command-line mount -t "ntfs" -o "uhelperudisks2,nodev,nosuid,uid0,gid0" "/…

Linux下的C语言文件编程

概念引入 window &#xff0c;linux如何修改一个文件&#xff0c;比如写一个word文档&#xff1a; 打开/创建文件 -->编辑文件 -->保存文件 -->关闭文件 我们需要使用代码自动化完成以上操作: 操作系统(linux)给我们提供了一系列的API: 打开&#xff1a; open 读写:…

【攻防世界】mfw(.git文件泄露)

首先进入题目环境&#xff0c;检查页面、页面源代码、以及URL&#xff1a; 发现页面无异常。 使用 dirsearch 扫描网站&#xff0c;检查是否存在可访问的文件或者文件泄露&#xff1a; 发现 可访问界面/templates/ 以及 .git文件泄露&#xff0c;故使用 GItHack 来查看泄露的 …

C语言奇技淫巧之--用宏定义替换函数名的另外一种思路

时间有限&#xff0c;简要记录原理。 快速回忆要点&#xff1a; #if definde(FEATURE_A) #define myfunc _myfunc #endif int myfunc(int a, int b) 场景&#xff1a; 假设某个功能函数针对不同的makefile配置需要有不同的函数名字&#xff0c;通常做法如下&#xff1a; #if …

传统方法(OpenCV)_车道线识别

一、思路 基于OpenCV的库&#xff1a;对视频中的车道线进行识别 1、视频处理&#xff1a;视频读取 2、图像转换&#xff1a;图像转换为灰度图 3、噪声去除&#xff1a;高斯模糊对图像进行去噪&#xff0c;提高边缘检测的准确性 4、边缘检测&#xff1a;Canny算法进行边缘检测…

状态模式(行为型)

目录 一、前言 二、状态模式 三、总结 一、前言 状态模式(State Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许一个对象在其内部状态改变时改变它的行为。对象看起来好像修改了它的类&#xff0c;但实际上&#xff0c;由于状态模式的引入&#xff0c;行为的变…

Python单元测试pytest捕获日志输出

使用pytest进行单元测试时&#xff0c;遇到了需要测试日志输出的情况&#xff0c;查看了文档 https://docs.pytest.org/en/latest/how-to/capture-stdout-stderr.html https://docs.pytest.org/en/latest/how-to/logging.html 然后试了一下&#xff0c;捕捉logger.info可以用…

CentOS 7.9 额外安装一个Python3.x版本详细教程

Centos7默认的python版本是2.7&#xff0c;根据需要我们额外安装一个Python3.x版本。 1、安装基础环境 yum update -yyum -y groupinstall "Development tools"yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel psmisc …

ArchiveBo

目录 1、 ArchiveBo 2、 BackResponseBo 3、 RelationshipVoKey 3.1、 * 内容主键 3.2、 * 项目主键

大语言模型及提示工程在日志分析任务中的应用 | 顶会IWQoS23 ICPC24论文分享

本文是根据华为技术专家陶仕敏先生在2023 CCF国际AIOps挑战赛决赛暨“大模型时代的AIOps”研讨会闪电论文分享环节上的演讲整理成文。 BigLog&#xff1a;面向统一日志表示的无监督大规模预训练方法 BigLog: Unsupervised Large-scale Pre-training for a Unified Log Represen…