提示:文章
文章目录
前言
前期疑问:
本文目标:
一、背景
2024年9月10日18:50:11
在看代码规范的时候又看到头文件相关的知识点,今天又再次整理一下,对头文件的使用又加深了理解。以前会莫名其妙报些告警,现在遇到应该会好处理了。
上述表述等于是将头文件中哪些可以定义哪些不能定义整理了一下
之前整理的文章是这一篇关于头文件,这次整理时也参考了这篇文章,而且再次看这篇文章的时候有了新的发现。真不错!**
二、
2.1 constexpr定义的变量是否可以放在头文件中
想把constexpr int STATISTICS_MAP_MAX_SIZE = 24 * 6 * 200;放在头文件中,就在疑惑能不能将const放在头文件中
1.在头文件中定义const类型的非static变量,在link时不会报错,这是因为const型的变量在complie时已经转换为常量,每个obj模块里有一个相同内容的常量,并不会有变量名冲突发生。
2.在头文件定义非const类型时,link时报错,这是因为这样相当于在每个包含该头文件的cc文件的全局域定义了一个名字相同的全局变量,虽然在complie时由于分开编译,不会产生错误,但是在link时,将会发生变量名冲突。
3.在头文件中使用extern 声明一个全局变量时可以的,而且是全局变量使用的推荐做法,前提是声明的这个全局变量,已经在一个cc文件,且只在一个cc文件中定义。
4.在头文件中定义的一个static变量,对于包含该头文件的所有源文件,实质上在每个源文件内定义了一个同名的static变量,他们仅为该源文件的全局变量而非全程序的全局变量。实际上在编译过程中,会为其每个obj模块中编译产生不同的名字,所以在link时候不会报错。但这样相当于在每个obj模块中有一个的static变量,它实际上是独立在每个obj模块中的文件级全局变量,不是全程序域的全局变量。
所以,在头文件中,最好只声明而不定义,定义也仅仅定义const型变量
2.2 结构体是否可以定义在头文件中
总之,结构体的定义位置根据项目的需要和结构体的使用范围来决定。如果需要在多个源文件中共享结构体定义,则应该放在头文件中;如果仅在一个源文件中使用,则可以直接在源文件中定义。
今天重新看了下之前的一篇文章,关于头文件,这篇文章之前是拷贝的其他文章,有缺失,但是今天看了下发现了一个知识点,即之前我在疑问,结构体能否写在头文件中,今天看到那篇文章写到。不能写在头文件中的是变量和函数。
当然结构体可以定义在头文件中,但是如果只有一个源文件使用,就可以写在源文件中。
关于头文件不能定义函数和变量,有几个例外,看到一个文章说的比较好:
参考《C++ Primer中文版》第四版 人民邮电出版社 P58:
因为头文件包含在多个源文件中,所以不应该含有变量或函数的定义。
对于头文件不应该含有定义这一规则,有三个例外。头文件可以定义类、值在编译时就已经知道的const对象和inline函数。这些实体可在多个源文件中定义,只要每个源文件中的定义是相同的。
在头文件中定义这些实体,是因为编译器需要它们的定义(不只是声明)来产生代码
类定义含类作用域内的函数与变量定义,也就是成员函数与数据成员。
1、内成员函数如果隐式内联了,当然没有问题,可以放在头文件中。否则,如果显示内联,可以放在头文件中。如若不然,放在头文件中可能引起重复定义。
2、数据成员:静态成员定义放在头文件中,可能会引起重复定义。非静态数据成员定义在类实例化的时候,才定义。
从根本上分析的话,还得从链接属性上分析。
上述表述等于是将头文件中哪些可以定义哪些不能定义整理了一下
三、头文件相互引用相关
3.1 禁止头文件相互引用
看代码规范,提到禁止头文件相互引用。之前好像遇到过头文件相互依赖,当时肯定很懵逼啊,而且在实际开发中遇到就很捉急。现在就此深化理解一下。
因为当时出现头文件循环依赖的时候并没有专门去记录。只是回退了操作。
现在参考规范,写了个循环依赖的示例。
代码如下:
// Foo.h文件
// Foo.h文件
#ifndef TESTPROJ_LOCAL_WITHOUT_LIBRARY_FOO_H
#define TESTPROJ_LOCAL_WITHOUT_LIBRARY_FOO_H
#include "Container.h"
class Foo {
Container* container;
};
#endif //TESTPROJ_LOCAL_WITHOUT_LIBRARY_FOO_H
// Conatiner.h文件
// Conatiner.h文件
#ifndef TESTPROJ_LOCAL_WITHOUT_LIBRARY_CONTAINER_H
#define TESTPROJ_LOCAL_WITHOUT_LIBRARY_CONTAINER_H
#include <iostream>
#include <map>
#include "Foo.h"
class Container {
std::map<std::string, Foo> table;
};
#endif //TESTPROJ_LOCAL_WITHOUT_LIBRARY_CONTAINER_H
// main.cpp文件
#include "Foo.h"
#include "Container.h"
int main()
{
Foo foo;
Container container;
std::cout << "program ok" << std::endl;
return 0;
}
上述代码创建在一个工程中,会报错如下
D:/AppData/CLion/testProj_local_without_library/headFileInclude/Container.h:14:27: error: 'Foo' was not declared in this scope
14 | std::map<std::string, Foo> table;
| ^~~
D:/AppData/CLion/testProj_local_without_library/headFileInclude/Container.h:14:30: error: template argument 2 is invalid
对于这个错误我一开始是不好理解的,查了资料
循环依赖是一种设计上的问题,需要避免。如果发生了循环依赖,编译器可能会报错或警告,并阻止代码的编译通过。解决循环依赖问题的最佳方法是重新设计代码结构,以消除循环依赖。
感觉编译器是禁止编译通过。、
这个问题怎么解决呢?使用类前置声明。
3.2 c++类前置声明
修改成下述形式:
// Foo.h文件
// Foo.h文件
#ifndef TESTPROJ_LOCAL_WITHOUT_LIBRARY_FOO_H
#define TESTPROJ_LOCAL_WITHOUT_LIBRARY_FOO_H
#include "Container.h"
class Foo {
Container* container;
};
#endif //TESTPROJ_LOCAL_WITHOUT_LIBRARY_FOO_H
// Conatiner.h文件
// Conatiner.h文件
#ifndef TESTPROJ_LOCAL_WITHOUT_LIBRARY_CONTAINER_H
#define TESTPROJ_LOCAL_WITHOUT_LIBRARY_CONTAINER_H
#include <iostream>
#include <map>
//#include "Foo.h"
class Foo;
class Container {
std::map<std::string, Foo> table;
};
#endif //TESTPROJ_LOCAL_WITHOUT_LIBRARY_CONTAINER_H
// main.cpp文件
#include "Foo.h"
#include "Container.h"
int main()
{
Foo foo;
Container container;
std::cout << "program ok" << std::endl;
return 0;
}
就可以成功编译程序并执行
然后突然意识到这是对于c++代码类的解决办法。如果是c语言循环依赖该怎么解决?
暂时先不管这个。先解决上述类的问题。
我想到的一个就是重新设计代码。
总结
未完待续
标签:Foo,头文件,定义,LIBRARY,关于,include,TESTPROJ From: https://blog.csdn.net/2301_77560238/article/details/142106377