C++的头文件(通常以.h或.hpp为扩展名)一般包含以下内容:
- 函数声明:函数的原型,使其他源文件可以调用这些函数。
- 类和结构体的声明与定义:包罗成员变量和成员函数的声明。
- 模板类和模板函数的定义:模板必要在编译时完全可见,所以实在现通常放在头文件中。
- 宏定义:利用#define预处理指令定义的宏。
- 类型定义:利用typedef或using创建的类型别名。
- 枚举类型的定义:enum类型的声明。
- 内联函数的定义:利用inline关键字的函数,实在现通常放在头文件中。
- 外部变量的声明:利用extern关键字声明的全局变量。
- 定名空间的声明和利用:定义定名空间以组织代码。
- 预处理指令:如包含掩护(include guard)#ifndef/#define/#endif或#pragma once,防止头文件被重复包含。
头文件的主要作用是声明接口,使多个源文件可以共享代码。在头文件中通常不包含函数的具体实现(模板和内联函数除外),以克制链接时的重复定义错误。
在C++中,函数的重复声明通常不会有问题,编译器允许对同一函数进行多次声明。但是,重复定义函数(即提供函数的实现)是不允许的。
以下是一些在C++中不能重复声明或定义的情况:
- 变量定义:
- 全局变量:全局变量只能定义一次。假如在多个地方对同一变量进行了定义(而非声明),链接时会产生“multiple definition”错误。
- 静态变量:静态变量也只能在同一作用域内定义一次,重复定义会导致编译错误。
- 类、结构体和枚举类型的定义:
- 类和结构体:同一作用域内不能重复定义同名的类或结构体。这会导致编译器报类型重定义的错误。
- 枚举类型:同样,枚举类型也不能在同一作用域内重复定义。
- typedef和using类型别名:
- 类型别名:在同一作用域内,不能对同一名称重复定义类型别名。这会引发编译错误。
- 函数定义:
- 非内联、非模板函数:函数的实现(定义)只能出现一次。重复定义会在链接阶段产生“multiple definition”错误。
- 内联函数:内联函数可以在多个翻译单元中定义,但必须保持同等。假如没有inline关键字,重复定义会导致错误。
- 宏定义:
- 宏重复定义:假如在未利用#undef的情况下重复定义宏,而且新定义与原定义不同,大概会产生警告或错误。
- 模板定义:
- 模板类和模板函数:模板的定义一般放在头文件中,但假如头文件没有包含掩护,大概会导致重复定义错误。
- 定名空间别名和using声明:
- 定名空间别名:在同一作用域内,不能对同一名称重复创建定名空间别名。
- using声明:重复的using声明固然不会导致错误,但大概会引起代码混淆。
为什么必要包含掩护(Include Guard):
当一个头文件被多个源文件包含,或者在同一个源文件中被间接多次包含时,假如没有包含掩护,以上提到的实体大概会被重复定义或声明,导致编译错误或链接错误。利用包含掩护可以确保头文件的内容在同一个翻译单元中只被处理一次,克制重复定义和声明的问题。
示例:
假设有一个头文件myheader.h:
- // myheader.h
- struct MyStruct {
- int data;
- };
复制代码 假如在源文件中多次包含myheader.h,而没有包含掩护:
- #include "myheader.h"
- #include "myheader.h" // 重复包含
- int main() {
- MyStruct obj;
- return 0;
- }
复制代码 编译时会报错,提示MyStruct重复定义。添加包含掩护可以解决这个问题:
- // myheader.h
- #ifndef MYHEADER_H
- #define MYHEADER_H
- struct MyStruct {
- int data;
- };
- #endif // MYHEADER_H
复制代码 总结:
- 重复声明:通常是允许的,如函数和变量的extern声明。
- 重复定义:在同一作用域或翻译单元中,类型、变量、函数等的重复定义是不允许的。
- 包含掩护:利用#ifndef/#define/#endif或#pragma once可以防止头文件内容被重复处理,克制重复定义和声明的问题。
通过明白这些规则,可以编写更结实的C++代码,克制因重复定义导致的编译和链接错误。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |