初学C++ 这个错误定义标签原因是重复定义 怎么改啊

  C++由于头文件重复包含了所定义的變量或者常量编译器就会报重复定义的错误定义标签。如果你碰见这样的问题可以考虑重下面几个方面去解决:

  1、在出现重定义错误定義标签的头文件加上:

   注意如果FileName_H_这个名字已经被使用将会出现未定义问题(这里不讨论),这是你保证FileName_H_唯一就可以

  2、在出现重定义错誤定义标签的头文件加上这一句:#pragma once 就可以解决(VS建立的类都会默认添加这一行),方式2与1其实是一样的二选一即可(个人推荐使用方式1)

    采用方式1或方式2基本上可以解决95%以上的重复定义的问题。在开发过程中经常会使用第三方的API,单独使用某一个API都正常但是同时使用多個API的时候就会出现某些结构体重复定义的问题,此时可以按照下面几种方式处理:

    3、将重复定义的struct、变量名、常量提出到一个公共的.h文件中,然后将原文件中公共部分的struct、变量名、常量屏蔽或删除同时在头文件中包含公共的.h文件。

 4、如果三防库中出现C风格、C++风格两种鈈同的struct定义方式,就不能按照3的方式解决了(方式3解决后编译正常但是会出现链接问题,分析lib中的导出函数中参数与C风格参数差异此时只需要将C风格方式的struct修改为C++风格的struct,同时更新API头文件中对应使用C风格struct位置

加载中,请稍候......

以上网友发言只代表其个人观点不代表噺浪网的观点或立场。

}

一、同一头文件中类嵌套的疑问

假设我们有两个类A和B分别定义在各自的头文件A.h和B.h中,但是在A中要用到BB中也要用到A,像下面的写法是错误定义标签的:

a;};因为在A对象中要開辟一块属于B的空间而B中又有A的空间,是一个逻辑错误定义标签无法实现的。在这里我们只需要把其中的一个A类中的B类型成员改成指針形式 就可以避免这个无限延伸的怪圈了为什么要更改A而不是B?因为就算你在B中做了类似的动作也仍然会编译错误定义标签,表面上這仅仅上一个先后顺序的问题      为什么会这样呢?因为C++编译器自上而下编译源文件的时候对每一个数据的定义,总是需要知道定义的数據的类型的大小在预先声明语句class 'B'将A中的b更改为B指针类型之后,由于在特定的平台上指针所占的空间是一定的(在Win32平台上是4字节),这樣可以通过编译

二、不同头文件中的类的嵌套在实际编程中,不同的类一般是放在不同的相互独立的头文件中的这样两个类在相互引鼡时又会有不一样的问题。重复编译是问题出现的根本原因为了保证头文 件仅被编译一次,在C++中常用的办法是使用条件编译命令

为什麼会出现类重复定义的错误定义标签呢?请读者仔细查看EX10.cpp文件在这个文件中包含了animal.h和fish.h这两个头文件。当编译器编译EX10.cpp文件时因为在文件Φ包含了animal.h头文件,编译器展开这个头文件知道animal这个类定义了,接着展开fish.h

要解决头文件重复包含的问题可以使用条件预处理指令

     我们洅看EX10.cpp的编译过程当编译器展开animal.h头文件时,条件预处理指令判断ANIMAL_H_H没有定义于是就定 义它,然后继续执行定义了animal这个类;接着展开fish.h头文件,而在fish.h头文件中也包含了animal.h再次展开 animal.h,这个时候条件预处理指令发现ANIMAL_H_H已经定义于是跳转到#endif,执行结束


但是不要以为使用了这种机制僦全部搞定了,比如在以下的代码中:

这里两者都使用了指针成员因此嵌套本身不会有什么问题,在主函数前面使用#include "A.h"之后主要编译错誤定义标签如下:

specifiers仍然是类型不能找到的错误定义标签。其实这里仍然需要前置声明分别添加前置声明之后,可以成功编译了代码形式如下:

这样至少可以说明,头文件包含代替不了前置声明有的时候只能依靠前置声明来解决问题。我们还要思考一下有了前置声明嘚时候头文件包含还是必要的 吗?我们尝试去掉A.h和B.h中的#include行发现没有出现新的错误定义标签。那么究竟什么时候需要前置声明什么时候需要头文件包含呢?

头文件包含其实是一件很烦琐的工作不但我们看着累,编译器编译的时候也很累再加上头文件中常常出现的宏定義。感觉各种宏定义的展开是非常耗时间的远不如自定义函数来得速度。我仅就不同头文件、源文件间的句则结构问题提出两点原则僅供参考:


第一个原则应该是,如果可以不包含头文件那就不要包含了。这时候前置声明可以解决问题如果使用的仅仅是一个类的指針,没有使用这个类的具体对象(非指针)也没有访问到类的具体成员,那么前置声明就可以了因为指针这一数据类型的大小是特定嘚,编译器可以获知


第二个原则应该是,尽量在CPP文件中包含头文件而非在头文件中。假设类A的一个成员是是一个指向类B的指针在类A嘚头文件中使用了类B的前置声明并编译成功,那么在A的实现中我们需要访问B的具体成员因此需要包含头文件,那么我们应该在类A的实现蔀分(CPP文件)包含类B的头文件而非声明部分

}

到目前为止C++ 仍然是计算机编程領域的经典语言之一,C++ 17 标准在2017上半年已经讨论确定本期我们汇集了编程专家——祁宇(《深入应用 C++ 11》作者,C++ 开源社区 /apolukhin/magic_get)这个库也准备進入 boost。我们来看看 magic _ get 的使用示例

 
上面的代码在编译期将类型 int 和 char 做了一个编码,将类型转换为一个具体的编译期常量后面就可以根据这些編译期常量来获取对应的具体类型。
编译期根据 id 获取 type 的代码如下:
 
上面的代码中 id _ to _ type 返回的是 id 对应的类型的实例如果要获取 id 对应的类型还需偠通过 decltype 推导出来。magic _ get 通过一个宏将 pod 基本类型都做了一个编码以实现 type 和 id 在编译期的相互转换。
 
将类型编码之后保存在哪里以及如何取出来昰接着要解决的问题。magic _ get 通过定义一个 array 来保存结构体字段类型 id
 
array 中的定长数组 data 中保存字段类型对应的 id,数组下标就是字段在结构体中的位置索引

萃取 pod 结构体字段

 
前面介绍了如何实现字段类型的保存和获取,那么这个字段类型是如何从 pod 结构体中萃取出来的呢具体的做法分为彡步:
  • 定义一个保存字段类型 id 的 array;
  • 将 pod 的字段类型转换为对应的 id,按顺序保存到 array 中;
  • 筛除 array 中多余的部分
 
 
定义 array 时需要定义一个固定的数组长喥,长度为多少合适呢应按结构体最多的字段数来确定。因为结构体的字段数最多为 sizeof(T)所以 array 的长度设置为 sizeof(T)。array 中的元素全部初始化为0一般情况下,结构体字段数一般不会超过 array 的长度那么 array 中就就会出现多余的元素,所以还需要将 array 中多余的字段移除只保存有效的字段类型 id。具体的做法是计算出 array 中非零的元素有多少接着再把非零的元素赋给一个新的 array。下面是计算 array 非零元素个数同样是借助 constexpr 实现编译期计算。
 

 

 
这个结构体比较特殊我们先把它简化一下。
这个结构体的特殊之处在于它可以用来构造任意 pod 类型比如 int、char、double 等类型。
因为 ubiq 构造函数所需要的类型由编译器自动推断出来所以它能构造任意 pod 类型。通过 ubiq 结构体获取了需要构造的类型之后我们还需要将这个类型转换为 id 按顺序保存到定长数组中。
 
上面的代码中先将编译器推导出来的类型转换为 id然后保存到数组下标为 I 的位置。
 


将 pod 结构体字段 id 保存到数组中之后接下来就需要将数组中的 id 列表转换为 tuple 了。
 
pod 字段 id 序列转换为 tuple 的具体做法分为两步:
 
下面是具体的实现代码:
 
 
id _ to _ type 返回的是某个 id 对应的类型实例所以还需要 decltype 来推导类型。这样我们就可以根据 T 来获取一个 tuple 类型了接下来是要将 T 的值赋给 tuple,然后就可以根据索引来访问 T 的字段了
 
对于 clang 編译器,pod 结构体是可以直接转换为 std::tuple 的所以对于 clang 编译器来说,到这一步就结束了
 
然而,对于其他编译器如 msvc 或者 gcc,tuple 的内存并不是连续的不能直接将 T 转换为 tuple,所以更通用的做法是先做一个内存连续的 tuple然后就可以将 T 直接转换为 tuple 了。
 
下面是实现内存连续的 tuple 代码:
 
 
这样就可以通过 get 就可以获取 tuple 中的元素了
到此,magic _ get 的核心代码分析完了由于实际的代码会更复杂,为了让读者能更容易看懂我选取的是简化版的代碼,完整的代码可以参考 GitHub 上的 或者简化版的代码
 
get 无需额外的负担和代码就可以实现编译期反射的特点,很适合做 ORM 数据库访问引擎和通用嘚序列化/反序列化库我相信还有更多潜力和应用等待我们去发掘。
Modern C++ 的一些看似平淡无奇的特性组合在一起就能产生神奇的魔力让人不禁赞叹 Modern C++ 蕴藏了无限的可能性与神奇。
 
 
 
 
 
 
}

我要回帖

更多关于 错误定义标签 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信