C++ 错题本--duplicate symbol问题
顾名思义, duplicate symbol是重复符号的意思!
代码是用来做什么的(问题缘由 & 代码结构)
写排序算法, 提出了一个公共的头文件用来写一些工具方法, 比如打印数组内容. 以便于不同文件代码需要打印数组内容的时候,直接引入相关头文件即可, 但是编译时出现了 duplicate symbol 报错.
总共涉及四个文件
● InsertSort.h, InsertSort.cpp : 插入排序算法实现部分
● CollectionUtil.h : 数组集合相关工具方法, 如打印数组
● main.cpp : 输入待排序数组,以及调用排序算法
代码如下
CollectionUtil.h : 数组集合相关工具方法, 如打印数组
#ifndef ALGORITHM_COLLECTIONUTIL_H
#define ALGORITHM_COLLECTIONUTIL_H
#include <iostream>
using namespace std;
void printArray(int size, int a[]) {for (int i = 0; i < size; ++i) {cout << a[i] << ",";}cout << endl;
}#endif //ALGORITHM_COLLECTIONUTIL_H
InsertSort.h, InsertSort.cpp : 插入排序算法实现部分
InsertSort.h
#ifndef ALGORITHM_INSERTSORT_H
#define ALGORITHM_INSERTSORT_H
class InsertSort {
public:
//折半插入排序
void halfInsertSort(int size, int a[]);
};#endif //ALGORITHM_INSERTSORT_H
nsertSort.cpp
#include "InsertSort.h"
#include <iostream>
#include "../common/CollectionUtil.h"using namespace std;
/*** 折半插入排序* 新选的比较值, 在与前面排好的有序队列比较的时候, 采取二分思想,找到合适的位置* @param size* @param a*/
void InsertSort::halfInsertSort(int size, int *a) {// ... 排序算法代码省略 ...printArray(size, a);}
}
main.cpp : 输入待排序数组,以及调用排序算法
#include "sort/InsertSort.h"
#include "common/CollectionUtil.h"
using namespace std;
int main() {int a[] = {20, 64, 23, 12, 9, 53, 2,88};InsertSort insertSort;int size = sizeof(a) / sizeof (int);// 折半插入排序insertSort.halfInsertSort(size, a);printArray(size, a);return 0;
}
编译时出现问题,报错如图所示:
解
将ClollectionUtil.h 写一个专门的cpp实现, 里面含有对printArray 全局函数的定义.即可
如改为:
ClollectionUtil.h
#ifndef ALGORITHM_COLLECTIONUTIL_H
#define ALGORITHM_COLLECTIONUTIL_H
void printArray(int size, int a[]);
#endif //ALGORITHM_COLLECTIONUTIL_H
CollectionUtil.cpp
#include "CollectionUtil.h"
#include <iostream>
using namespace std;
void printArray(int size, int a[]) {for (int i = 0; i < size; ++i) {cout << a[i] << ",";}cout << endl;
}
原因:
C++中, 多文件编译, 整个横向的跨度上, 对于函数而言, 允许多次声明, 一次定义. 但是不允许多次声明, 多次定义. 代码原来的写法,正是促成了 "多次声明多次定义"的情况, 是不符合其标准的.
我们需要重新审视一下, #include 在预编译的时候到底做了什么, 过往仅仅是一个单独文件的编译, 我们知道就是把被引入的内容代码进行了全拷贝. 但是为什么编译多个文件的时候, 上述代码多个文件引入了相同的头文件, 头文件里明明做好了 #ifndef #define #undef 之类的保护, 就拷贝那么一次, 为什么还是冲突了呢? 原因在于C++编译器,对于文件的编译, 是分开编译的. 虽然说定义一个全局的宏, 是全局可见, 但是编译时由于分开编译, 会导致如图所示:
根据图示, 预处理的时候, 尽管存在ifndef define等宏定义, 但是最终出来的结果是, 全局存在两处 printArray 函数的定义. 不符合标准. 解决办法就是, 把头文件中内容改为只声明printArray()函数, 而不让其有定义, 定义写在cpp文件中, 这样尽管全局会出现多次声明, 但依然符合标准.
总结及扩展
C++允许多次声明, 一次定义. 定义指的是,写出具体实现逻辑的方法.
C++编译的时候会分开编译.
C++头文件,最好不要带函数的定义。
相关文章:

C++ 错题本--duplicate symbol问题
顾名思义, duplicate symbol是重复符号的意思! 代码是用来做什么的(问题缘由 & 代码结构) 写排序算法, 提出了一个公共的头文件用来写一些工具方法, 比如打印数组内容. 以便于不同文件代码需要打印数组内容的时候,直接引入相关头文件即可, 但是编译时出现了 duplicate sym…...

Cursor的chat与composer的使用体验分享
经过一段时间的试用,下面对 Composer 与 Chat 的使用差别进行总结: 一、长文本及程序文件处理方面 Composer 在处理长文本时表现较为稳定,可以对长文进行更改而不会出现内容丢失的情况。而 Chat 在更改长的程序文件时,有时会删除…...

【优选算法 — 滑动窗口】最大连续1的个数 将 x 减到0的最小操作数
最大连续1的个数 最大连续1的个数 题目描述 题目解析 给我们一个元素全是0或者1的数组,和一个整数 k ,然后让我们在数组选出最多的 k 个0;这里翻转最多 k 个0的意思,是翻转 0 的个数< k,而不是一定要翻转 k …...

《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址
《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址 《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址域名系统什么是域名?DNS 服务器IP 地址和域名之间的转换使用域名的必要性利用域名获取 IP 地址利用 IP 地址获取域名 基于 Wi…...
FastHTML快速入门:调试模式和 URL中的变量
调试模式 FastHTML基于FastAPI友好的装饰器模式来指定URL,并添加了额外功能: main.py from fasthtml.common import * app, rt fast_app() rt("/") def get():return Titled("FastHTML", P("让我们开始吧!"…...

C++高级编程(8)
八、标准IO库 1.输入输出流类 1)非格式化输入输出 2)put #include <iostream> #include <string> using namespace std; int main() {string str "123456789";for (int i str.length() - 1; i > 0; i--) {cout.put(str[i]); //从最后一个字符开…...

AUTOSAR_EXP_ARAComAPI的7章笔记(2)
☞返回总目录 相关总结:服务发现实现策略总结 7.2 服务发现的实现策略 如前面章节所述,ara::com 期望产品供应商实现服务发现的功能。服务发现功能基本上是在 API 级别通过 FindService、OfferService 和 StopOfferService 方法定义的,协议…...

【C++】 C++游戏设计---五子棋小游戏
1. 游戏介绍 一个简单的 C 五子棋小游戏 1.1 游戏规则: 双人轮流输入下入点坐标横竖撇捺先成五子连线者胜同一坐标点不允许重复输入 1.2 初始化与游戏界面 初始化界面 X 输入坐标后 O 输入坐标后 X 先达到胜出条件 2. 源代码 #include <iostream> #i…...

仿RabitMQ 模拟实现消息队列项目开发文档2(个人项目)
项目需求分析 核心概念 现在需要将这个项目梳理清楚了,便于之后的代码实现。项目中具有一个生产消费模型: 其中生产者和消费者的个数是可以灵活改变的,让系统资源更加合理的分配。消息队列的主逻辑和上面的逻辑基本一样,只不过我…...

李佳琦回到巅峰背后,双11成直播电商分水岭
时间倏忽而过,又一年的双11即将宣告结束。 从双11正式开始前的《新所有女生的offer》,到被作为“比价”标杆被其他平台直播间蹭、被与其他渠道品牌比较,再到直播间运营一时手快多发了红包……整个双11周期下来,李佳琦直播间在刷新…...

云计算在教育领域的应用
💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 云计算在教育领域的应用 云计算在教育领域的应用 云计算在教育领域的应用 引言 云计算概述 定义与原理 发展历程 云计算的关键技…...

C语言 | Leetcode C语言题解之第543题二叉树的直径
题目: 题解: typedef struct TreeNode Node;int method (Node* root, int* max) {if (root NULL) return 0;int left method (root->left, max);int right method (root->right, max);*max *max > (left right) ? *max : (left right);…...

6、If、While、For、Switch
6、If、While、For、Switch 一、If 1、if-else if (boolean) {代码块 } else if (boolean) {代码块 } else if (boolean) {代码块 } else { // 默认情况代码块 }关于IDEA单元测试控制台不能输入数据的问题: https://blog.csdn.net/m0_72900498/article/details/…...

萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
随着智慧城市和数字化转型的推进,视频监控系统已成为保障公共安全、提升管理效率的重要工具。特别是在大中型项目中,跨区域的网络化视频监控需求日益增长,这要求视频监控管理平台不仅要具备强大的视频资源管理能力,还要能够适应多…...
【多线程】线程池如何知道一个线程的任务已经完成
目录 1. 说明2. 任务的生命周期3. 状态更新4. 线程间的协作5. 内部数据结构6. 回调与通知7. 线程池的关闭与清理 1. 说明 1.线程池通过一系列内部机制来知道一个线程的任务已经完成。2.这些机制主要涉及任务的生命周期管理、状态更新以及线程间的协作。 2. 任务的生命周期 1…...

Transformer介绍(一)
Transformer是一种特殊的神经网络,一种机器学习模型。 谷歌在2017年推出的原版Transformer,论文《Attention Is All You Need》,专注于将一种语言的文本翻译成另一种。 而我们要关注的Transformer变种,即构建ChatGPT等工具的模型…...

[CKS] TLS Secrets创建与挂载
目前的所有题目为2024年10月后更新的最新题库,考试的k8s版本为1.31.1 BackGround 您必须使用存储在TLS Secret中的SSL文件,来保护Web 服务器的安全访问。 Task 在clever-cactus namespace中为名为clever-cactus的现有Deployment创建名为clever-cactu…...

java双向链表解析实现双向链表的创建含代码
双向链表 一.双向链表二.创建MyListCode类实现双向链表创建一.AddFirst创建(头插法)二.AddLast创建(尾叉法)三.size四.remove(指定任意节点的首位删除)五.removeAll(包含任意属性值的所有删除)六.AddIndex(给任意位置添加一个节点…...
【Kafka-go】golang的kafka应用
网络上关于go的Kafka还是比较少的今天就先出一篇入门级别的,之后再看看能能出一个公司业务场景中的消息流。 一、下载github.com/segmentio/kafka-go包 go get github.com/segmentio/kafka-go二、建立kafka连接 正常来说下面的配置host topic partition 应该写在…...

redis:set集合命令,内部编码,使用场景
个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 前言命令SADDSMEMBERSSISMEMBERSCARDSPOPSMOVESREM集合间操作SINTERSINTERSTORESUNIONSUNIONSTORESDIFFSDIFFSTORE 内部编码使用场景总结 前言…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...