C++中的类型重定义

VS2017的C++开发心得(十)头文件与重复定义符号 之前在这篇文章VS2017的C++开发心得(四)VS的文件夹路径以及项目生成步骤中谈到过关于在cpp中定义相同类型变量名导致的重复定义。 先看下什么是符号,我在main.cpp中定义了一个int test,同时又在a.cpp中定义了一个int test,编译会出现链接错误如下: 从上图可知,符号是由变量名和类型共同组成的,所以如果我a.cpp中定义的是 int test() { ... 阅读详情

C++中的类型重定义

这几天工作时碰到一个C++的编译错误(我使用的是Visual C++ 7.0),说是有一个类重复定义,仔细想想我们的这个项目也是做了好几个Release了, 内部代码应该不会有这样的低级错误, 真把类型给重复定义了,检查结果正如我预料的一样。 就这样, 我左右没找到原因,被一个编译错误给卡在那里了。(在我的概念中, 程序错误的等级为:编译错误->链接错误->逻辑错误, 此错误属于最低级 )。这时我仔细看了一下错误提示, 发现重复定义是由于从两个不同的路径包含了同一个头文件而引起的,同事也建议从另外一个路径打开工程试试, 这才慢慢发现了原因。这个原因可能有些拗口,而事实上要出现这种错误也有些”曲折”, 让我从不同情况下的类型重定义来解释一下吧。

我总结的类型重定义情况有三。

一、没有在文件头加#pragma once指示符。

Type1.h:
//#pragma once
class Type
{
};
Main.cpp:
#include "Type1.h"
#include "Type1.h"
int main(int argc, char *argv[])
{
   return 1;
}

这个#pragma once的作用是保证本文件只被编译一次,如果没有在Type1.h中加这句话,那么在main.cpp里面包含了两次Type1.h, 就相当于在main.cpp里面定义了两次Type类, 自然就是类型重定义了。

二、两个不同的头文件中定义了相同的类型(均有#pragma once)

Type1.h:
#pragma once
class Type
{

};
Type2.h:
#pragma once
class Type
{

};
Main.cpp:
#include "Type1.h"
#include "Type2.h"
int main(int argc, char *argv[])
{
   return 1;
}

这里main.cpp中同时包含了Type1.h, Type2.h两个头文件, 虽然其文件头都有#pragma once,但因为是不同的文件, 预编译器还是会两次把Type类的定义放在Main.cpp中, 所以也会出现了重定义。

三、从两个不同的路径包含了同一个头文件

前面两种是比较常见, 也是比较容易解决的情况, 而这里要讲的第三种情况, 比较少见, 而且一般出现在有虚拟映射盘的时候。(这样才能做到从两个不同的路径包含同一个头文件), 其他会在什么时候出现, 我还没想到, 知道的朋友顶一下:)。下面我来分析一下:

1) 有VC工程在D:\Test目录下。

2) 映射虚拟盘X为D:\Test.

不熟悉的网友可以按此操作: 开始->运行->在运行窗口输入:cmd->在cmd窗口输入:
Subst X: D:\Test

3) 该工程有文件Type1.h, main.cpp

#pragma once
class Type
{

};
Main.cpp:
#include "Type1.h"
#include "X:\Type1.h"
int main(int argc, char *argv[])
{
   return 1;
}

这里我们在main.cpp这样包含了两个头文件, 从本质上来讲, 它们都对应于物理盘D:\Test下的文件Type1.h, 是同一个文件。但在不同的操作下, VC对其有不同的解释。#include “X:\Type1.h”用的是绝对路径, 自然没有什么异议, 但#include “Type1.h”却有些变化:
假如我从D:\Test\下打开工程, 那么#include “Type1.h”其实就是#include “D:\Test\Type1.h”
假如从X:\下打开工程,那么#include “Type1.h”就解释为#include “X:\Type1.h”

4) 在D:\Test下打开工程, 编译, 出现类型Type重复定义错误
这种情况下,main.cpp预编译为:
Main.cpp:

#include "D:\Test\Type1.h"
#include "X:\Type1.h"
int main(int argc, char *argv[])
{
   return 1;
}
#pragma once

只保证本文件被编译一次, 这里VC将其认为是两个不同的文件, 所以都要编译, 出现编译错误自然也就不奇怪了。

当然, 这里如果从X:\ 下打开工程的话,VC就会认为都是从X:\Type1.h下包含这个文件,#pragma once起到了作用, 也就不会出现类型重定义了

四、总结

我在VC7, VC8,和Dev C++中都测试了第三种情况, 发现只有Dev C++是可以通过编译的。这可能是微软VC的#pragma once还不够智能吧,轻易的被Windows的虚拟盘给蒙蔽了双眼, 看不到其本质(只是猜测, 或许VC这么处理是有其他用意的)。

因为在稍大一点的工程开发中, 我们一般都会用虚拟盘来方便工作, 一是访问快捷,简化了路径, 二是因为多人协同开发,我们一般希望大家源代码路径相同,但我们不应强制要求大家都把源代码放死在某一目录下, 这时把你放源代码的路径映射为一个虚拟盘(比如说统一为X:)就能把大家的代码路径统一起来了。但是另一方面,有了虚拟盘, 就为出现类型重定义提供了条件, 以下是我得出的两个解决方法:

1) 抛弃#pragma once使用古老但集稳定性与移植性于一身的

#ifndef _XXX_H
#define _XXX_H
//...
#endif

来保证头文件只被编译一次。这样不管是包含两个相同的文件,还是包含两个不同的文件,或是包含两个文件相同但路径不同的文件, 只要_XXX_H被定义过, 就不会再编译那个编译(但这里我们要保证_XXX_H的唯一性, 如果两个不同的头文件里用了同一_XXX_H,是会出问题的)

2) 在包含头文件时,不要使用绝对路径, 哪怕那是虚拟盘

VS C++重定义总结 这里写自定义目录标题VS C++重定义总结多处文件包含变量或类型重定义VS中函数定义与函数声明在一个头文件中 VS C++重定义总结 目前碰到的C++重定义总结 多处文件包含 // 文件A.h class A{} //文件B.h #include"A.h" class B{ A a; } //文件C.h #include"A.h" class C{ A a; } 如代码所示文件B、C同时include“A.h",导致重定义,改进方法 // 文件A.h #ifndef _A_H_ #define _A 阅读详情

相关推荐

博途的HMI(触摸屏)的应用

触摸屏(HMI):用于控制PLC,可认为是小型上位机(用于控制PLC的都可认为是上位机)上位机(PC Station):将触摸屏升级为电脑----工控机(工业控制的机器)用博途编写西门子的触摸屏和上位机。

王阿妹小天才的博客 2676

c++ 类型重定义

c++ 类型重定义

进击吧 510

JavaScript 书签脚本实战:腾讯/优酷/爱奇艺等5大视频站m3u8链接一键提取

本文详细介绍了如何使用JavaScript书签脚本一键提取腾讯视频、优酷、爱奇艺等五大视频平台的m3u8流媒体链接。通过分析播放器内部对象结构,开发者可以高效获取视频源文件,避免录屏画质损失。文章包含各平台适配方案、实战增强功能开发及企业级解决方案设计,帮助用户快速掌握这一实用技术。

weixin_27945229的博客 609

C++:重定义:class类型重定义

C++:重定义:class类型重定义

C++ JAVA的专栏 5595

【新华三】通过路由复制实现Public与VRF路由互通

如上图所示,S6900设备里有两张表,一张是public路由表,默认所有的路由都存放在public路由表里;除此之外还创建了VRF test,因此此设备还有VRF test路由表。通过路由复制实现Public路由和VRF路由互通,默认情况下VRF里的路由单独一张路由表,默认情况下与public路由表相互隔离,两张表之间不可互访。此时的public路由表里面并没有test的路由表。public路由表与VRF路由表之间相互隔离。此时VRF test里的路由也没有其他VRF或Public里的路由,相互隔离。

五大连池的镜子 5279

团结引擎+OpenHarmony 记录 (持续更新中)

获取不到的原因是因为二者不在同一个线程中,所以数据没有同步。而 globalThis.context 数据进行了同步。(TuanjieMainWorkerHandler.ts中可以看到)在进行绘制 UI 的时候 ,如果组件有 Native API 就可能不会显示出来,例如 web 控件就不能展示出来,刚加上权限的时候 会报错 因为缺少 reason ,添加上就不会报错了。只有纯 UI 控件是可以展示出来的,注释掉 web控件后就可以。

m_cainiaokuaifei的博客 1491

C++中重定义,重载,重写

C++中的重定义指在同一作用域内定义了同名的函数、变量或类型。重定义是编译器无法处理的语法错误,将导致程序无法编译通过。例如,在同一作用域内定义了两个函数名相同、参数列表相同的函数,就会产生重定义错误。C++中的重定义指在同一作用域内定义了同名的函数、变量或类型。重定义是编译器无法处理的语法错误,将导致程序无法编译通过。例如,在同一作用域内定义了两个函数名相同、参数列表相同的函数,就会产生重定义错误。如下是一个示例:```int add(int x, int y) { // 重定义。

weixin_46326585的博客 1978

ChatGPT and Claude国内使用站点

这篇博客介绍了不同的AI聊天平台和定价信息,主要对比了ChatGPT和Claude两款产品。文章列出了多个提供聊天服务的AI平台,包括RawChat、ChatGPTPlus、ChatOpens、Wildcard和2233.ai等,并提供了每个平台的网页链接和定价详情。特别关注了Claude平台,介绍了其普通账号与会员账号的不同,以及相关的定价信息。此外,还提到了一些虚拟卡定价和服务细节,为用户选择合适的AI服务提供了多种参考。

nisidjndn的博客 1万+

[转]C++中的类型重定义

By SmartPtr(http://www.cppblog.com/SmartPtr/) 这几天工作时碰到一个C++的编译错误(我使用的是Visual C++ 7.0),说是有一个类重复定义,仔细想想我们的这个项目也是做了好几个Release了,内部代码应该不会有这样的低级错误,真把类型给重复定义了,检查结果正如我预料的一样。就这样,我左右没找到原因,被一个编译错误给卡在那里...

weixin_30886233的博客 76

SCTPPortScan SCTP协议端口扫描、关联地址识别、传输状态检测

Windows:Winsock2+SCTP扩展)。- **SCTP API封装**:Linux下直接调用`socket()`、`connect()`、`getsockopt()`等系统函数,解析`struct sctp_status`和`struct sctp_paddrinfo`获取状态和关联地址。qDebug() << "开始SCTP扫描:" << ipList.size() << "个IP," << ports.size() << "个端口,共" << m_totalTasks << "个任务";

寒寒豆豆软件公司的博客 91

RDkit入门

今天开始写RDkit的入门教程,每天学习和写一小点,相信一句话“不积跬步无以至千里,不积小流无以成江海”,所以就慢慢来,一点一滴积累叭,从最简单的开始喽希望自己每天都能保持写博客的好习惯,把自己的代码笔记就极在这里,RDkit一块啃了很久的骨头,今天终于要下定决心,好好总结一波了,希望保持这个更新的频率,每天都能有所学。............

博客而已 6682

关于c/c++中的类型重定义错误的自己的理解

在头文件中定义一个结构体或者一个类,例如//global.htypedef struct book{ ... }Book;这样当在别的文件中使用这个结构的时候,可以用Book book;来声明变量。问题在于,不能在多个文件中多次包含global.h文件,否则这个头文件会执行多次,也就重复定义了。以上是自己的理解,希望有人指正。 -------------

an_ho的专栏 1021

C语言实现惯导更新算法(机械编排)

四元数可用于描述刚体转动或姿态变换,与方向余弦阵相比,表达简洁。四元数是一个包含四个元素的列向量,列向量的第一个元素表示刚体围绕旋转轴转过的角度大小,其余3个元素代表了旋转轴的方向。

十八与她的博客 1730

#include<*.cpp>用法问题

所谓 #include 的意思呢,就是把另一个文件里的东西复制到这里来,无论你的文件后缀是 h 还是 cpp 都是一样的。 如果#include了一个cpp,同时又把这个cpp包含到工程,链接时就会出现重定义错误。错误是怎么产生的呢?你可以试试写 a.cpp 和 b.cpp 两个文件,两个文件中有一模一样的两个函数,是不是产生了和你的问题中同样的错误?因为你有两个一模一样的函数,编译器不知道怎么

Lsheng1992的博客 4415

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

c++函数重载、重写、重定义区别与联系及协变

1.函数重载: 在C++种,函数重载是在同一作用域,函数名相同,但是参数列表:参数个数,参数类型,返回值(可同可不同)不同。总之,只要在同一作用域,只要函数名相同,就可构成函数重载。对于函数重载可查看这篇博客:https://mp.youkuaiyun.com/postedit/80551981 2.重定义(隐藏) 在基类和派生类中有同名成员,成员可以是变量,也可以是函数,如果是函数,不管参数或是返回值是否相...

sophia__yu的博客 3220

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

C++ 重载(overload)、重写(overrride)、重定义(redefine)总结

一、重载(overload) 指函数名相同,但是它的参数表列个数或顺序,类型不同。但是不能靠返回类型来判断。 (1)相同的范围(在同一个作用域中) ; (2)函数名字相同; (3)参数不同; (4)virtual 关键字可有可无。 (5)返回值可以不同; 二、重写(也称为覆盖 override) 是指派生类重新定义基类的虚函数,特征是: (1)不在同一个作用域(分别位于派生类与基类) ; (2)函...

1784

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

重载重写和重定义

重载重写与重定义 一:重载和重写理解 1:函数重载 必须在同一个类中进行 子类无法重载父类的函数,父类同名函数将被名称覆盖 重载是在编译期间根据参数类型和个数决定函数调用 2:函数重写 必须发生在父类和子类之间 并且父类与子类中的函数必须有完全相同的原型 使用virtual声明之后能够产...

guonengneng的博客 3222

C++枚举类型enum与enum class

文章目录一.关于枚举类型二.枚举类型enum的使用三.枚举类型enum class的使用 一.关于枚举类型 1. 什么是枚举类型? 答:如果一个变量只有几种可能的值,那么就可以定义为枚举类型,比如:性别只有男和女,那么就可以将性别定义为一种枚举类型,其中男和女就是性别所包含的变量。所谓”枚举”是指将变量的值一一列举出来,变量的值只能在列举出来的值的范围内。在C++中,枚举类型分为不限定作用域(enum)和限定作用域(enum class)。 2. enum与enum class的区别? (为什么需要

冬瓜的博客 1万+

C++重写(覆盖)、重载、重定义、多态

1 重写(覆盖)override override是重写(覆盖)了一个方法,以实现不同的功能。一般用于子类在继承父类时,重写(覆盖)父类中的方法。函数特征相同,但是具体实现不同。 重写需要注意: 被重写的函数不能是static的,必须是virtual的 重写函数必须有相同的类型,名称和参数列表 重写函数的访问修饰符可以不同。尽管virtual是private...

yihuanyihuan的博客 1875
上一篇: 求斐波那契(Fibonacci)数列通项的七种实现方法
下一篇: 第一天总结
TimEckel
博客等级 码龄10年 16粉丝 142原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值