如何看待C++前置声明?
C++前置声明 和 #include
c++中前置声明和#include
Qt 中类的 前向声明 和#include的区别 https://blog.csdn.net/ken2232/article/details/136126779
C++前置声明 和 #include https://blog.csdn.net/ken2232/article/details/136126609
====================================
如何看待C++前置声明?
https://www.zhihu.com/question/63201378
利益相关:在Google写了4年C++。
我是经历了Google内部从『倾向于使用前置声明』到『倾向于使用#include』的这个过程的。事实上在很多年前Google内部就开始了对这两者的比较和探讨。在2014年,内部有一篇总结性文章指出了前置声明
将造成的十种危险。最终C++ Code Style经历了一个过渡期之后全面倒向了#include。
简单来说,前置声明最大的好处就是『节省编译时间』。毕竟C++
的编译时间长已经是一个臭名昭著人人喊打的问题。但对于Google来说,这方面的效率节省就不见得那么可观了——毕竟Google内部有超大规模的分布式编译集群
『Forge』。哪怕是十万以上的target,全部build一遍也就是几分钟的事情。
与此同时,前置声明带来的问题则显得更加关键:
例如,如果一个类的实现者需要把这个类改个名字/换个命名空间
,出于兼容性他原本可以在原命名空间里/用原名通过using来起一个别名指向新类。然而别名不能被前向声明
。内网有一份代码改动一下子试图修改总计265个头文件,就是实现者为了要改这个类的名字而不得不去改所有的调用处。想一想,如果这265个文件分属于50个不同的团队,你得拿到50个人的同意才能提交这份改动,想不想打人?
再举一个code style中提到的,更为严重的例子——它可能导致运行时出现错误的结果:
// b.h:
struct B {};
struct D : B {};
// good_user.cc:
#include "b.h"
void f(B*);
void f(void*);
void test(D* x) { f(x); } // calls f(B*)
若把#include换成前置声明,由于声明时不知道D是B的子类
,test()中f(x)就会导致f(void*)被调用,而不是f(B*)。
再比如,C++标准5.3.5/5中规定,delete一个不完整类型的指针时,如果这个类型有non-trivial的析构函数
,那么这种行为是未定义的。把前置声明换成#include则能保证消除这种风险。
诚然,从理论上说,一个牛逼的程序员当然是可以通过分析一个头文件
的源码来决定会不会碰到以上诸多坑,并由此决定用哪个好。但一来不是所有人都是牛逼程序员,二来,把精力花费在这件事情上真的值得吗?
fullsail
前置声明最大的好处在于,避免编译膨胀。一个优秀的CPP代码应该只包含他的最小代码集合。
但前置声明并不能解决所有问题,他只在您的成员是指针时才能奇效,否则是必须使用#inlcude引入的相关头文件的,否则编译器无法知道结构的大小。而将成员都调整为指针,这个其实浪费了很多C++的编写优势(构造,析构等)。所以没有必要过分使用。如google那位兄弟说的,他们解决了编译的速度问题,就更不在乎使用前置声明了。但代码设计过程,还是会出现交叉引用,即使你再小心也不能完全避免。
乎用户
前置声明隐藏依赖啊亲们,扯什么编译时间啊。
没听说过 pImpl?
不用前置声明难道直接把 Windows.h 那一坨屎扔在头文件里让别人吃屎么……
乎用户
说简单点,就是尽量避免循环依赖
代码之诗
这个问题没必要长篇大论,我尽量简短:
- 头文件本身应当尽量减小不必要耦合,其中包括尽量少 include 引入无关要素;
- 代码规模较大时,前置声明容易发生“小修改引起大雪崩”。但这不是反对前置声明的理由,而应该把写前置声明的责任移交给写头文件的团队。象标准库一样,既有 iostream,又有 iosfwd。大家只需要 include,仍然享受到了前置声明的好处。
- 即使代码规模不大,相关的前置声明也可以自己写一个头文件,相对集中处理。
我的结论:尽可能使用前置声明,但不要写得到处都是。
作者:代码之诗
链接:https://www.zhihu.com/question/63201378/answer/2574824272
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
c++中前置声明和#include
https://blog.csdn.net/xiaofeilongyu/article/details/119859638
c++中前置声明和#include
- 能用前置声明的尽量用前置声明,尽可能的避免用#include头文件
- 尽量在cpp文件中包含头文件,而非在头文件中
。。。(略)。。。
编译器编译需要知道文件的大小,所以当类B中以指针的形式引用类A时可以使用前置声明,单若时用到了类A的对象那就必须使用#include包含类A的头文件
具体情况如下:
- B继承A,必须#include A.h,需要获得A的定义
- B有一个指针类型为A的成员变量,前置声明就可以
- B有一个引用类型为A的成员变量,前置声明
- B有一个不同类型为A的成员变量,需要使用#iclude A.h
- B用使用到标准模板库,例如vector< A >,前置声明九月可以,标准模板库内部使用的是指针作为成员变量
- B中有函数成员函数返回类型和参数为A的,前置声明
- B中有函数成员函数返回类型和参数为A的,并且在头文件中定义此函数并调用A中的成员或函数,需要#iclude A.h
。。。(略)。。。
使用前置声明可解决相互依赖头文件相互依赖问题
前置声明的作用
1、解决class相互依赖问题
2、降低文件之间的编译依赖关系
3、前置声明可以实现接口与实现分离,提供给客户的类分为两个class,一个用来提供接口,一个负责实现;
https://blog.csdn.net/u011913417/article/details/100183653
https://www.cnblogs.com/rednodel/p/5000602.html
C++前置声明 和 #include
https://www.cnblogs.com/sggggr/p/16938612.html
阅读目录
前置声明用处:
1.前置声明能够节省编译时间
2.在两个类相互引用时用前置声明
当然应当尽量避免这样设计,需要依赖倒置规避
3.前置声明,在写wrapper的时候,会发现是屏蔽内部宏定义的好方法
比如,需要写一个动态库,并提供头文件给别人使用,头文件是这样的
class ImgAnalysis;
DLL_EXPORT ImgAnalysis* create_img_analysis(const ImgAnalysisCfg *cfg);
DLL_EXPORT int run_img_analysis(ImgAnalysis* img_analysis, ImgAnalysisInput* input);
DLL_EXPORT void destory_img_analysis(ImgAnalysis* img_analysis);
ImgAnalysis这个类里面有很多成员变量,依赖其它很多头文件,如果不前置声明,就要放在这个头文件中,那别人使用这个头文件,就要把ImgAnalysis这个类需要的头文件全包含进来,有前置声明,这个头文件才能如此干净,使用的人也方便很多。如果没有前置声明,还有一种方法就是void指针,然后强制类型转换,不过我是极度讨厌void的,void*一眼看不出类型, 能不用就不用。
前置声明的劣势
例如,如果一个类的实现者需要把这个类改个名字/换个命名空间,出于兼容性他原本可以在原命名空间里/用原名通过using来起一个别名指向新类。然而别名不能被前向声明。内网有一份代码改动一下子试图修改总计265个头文件,就是实现者为了要改这个类的名字而不得不去改所有的调用处。想一想,如果这265个文件分属于50个不同的团队,你得拿到50个人的同意才能提交这份改动,想不想打人?
// b.h:
struct B {};
struct D : B {};
// good_user.cc:
#include "b.h"
void f(B*);
void f(void*);
void test(D* x) { f(x); } // calls f(B*)
若把#include换成前置声明,由于声明时不知道D是B的子类,test()中f(x)就会导致f(void)被调用,而不是f(B)。
等等
结论:
还是用#include比较稳妥,写库的时候可能会用到前置声明