#include.cpp模板实现文件是一种不好的做法吗?
Is #include'ing .cpp template implementation files a bad practice?
在我正在进行的一个项目中,我有一个相当大的模板类,我已经实现如下:
我有我的头文件
// MyBigClass.h
#ifndef MYBIGCLASS_H
#define MYBIGCLASS_H
template <typename T>
class MyBigClass {
/* -- snip -- */
};
#include "MyBigClass.cpp"
#include "MyBigClass_iterator.cpp"
#include "MyBigClass_complicatedFunctionality_1.cpp"
#include "MyBigClass_complicatedFunctionality_2.cpp"
#endif
然后我所有的实现文件基本上都是这样的:
// MyBigClass_foobar.cpp
template <typename T>
void MyBigClass<T>::member_1(){
/* -- snip -- */
}
template <typename T>
int MyBigClass<T>::member_2(int foo, T & bar){
/* -- snip -- */
}
// etc, etc
在main.cpp
中,我只包含了MyBigClass.h
,一切都很好地工作和编译。我之所以将实现拆分为许多文件,是因为我更喜欢处理三到四个200-400行的文件,而不是一个1200行的文件。文件本身在逻辑上组织得相当好,例如只包含嵌套类的实现,或一组相互关联的成员函数。
我的问题是,这是已经完成的事情吗?前几天当我把这个展示给别人时,我有一个奇怪的反应,所以我想知道这是不是一个糟糕的做法,或者是否有更好、更常见的方法来完成这样的事情。
按照惯例,通常不包括cpp
文件(这样做时会有有限的和奇异的情况),这可能是你得到奇怪外观的原因。
通常,这种分离是通过将实现移动到.impl
甚至.h
文件而不是cpp
文件来完成的。
不,分离模板的实现并将文件包含在头中并没有错。
所以。。。包含.cpp
是一种不好的做法,但是什么阻止您使用头文件而不是.cpp
?例如,提升使用.ipp
文件。。。
我曾处理过包含数千个或更多文件的C/C++项目,这是我通常观察到的做法:
- 将类定义保留在头文件中。不要在头文件中添加任何实现。内联函数和模板除外。我最终会明白的
- 将所有函数和方法实现保存在.c或.cpp文件中
这样做有其根本原因
- .h文件是任何人使用您在代码中实现的类/函数/和其他数据结构和API的参考点。任何不知道类结构的人都会先引用.h
- 您可以分发一个只显示.h文件的库,而不显示您的实际实现。通常,他们会提供外部API(同样在.h文件中),这些API是库中任何代码的唯一入口点,如果第三方希望共享代码,则可以使用这些API
- 如果在多个位置包含一个.c或.cpp文件(在编译过程中不会看到任何错误),但链接器会解决重复符号的问题。由于它有多个您包含的.c/.cpp文件中所有这些函数/方法的副本
异常
-
内联函数实现需要存在于.h文件中才能有效。有些情况下,编译器可能会自动决定一段代码可以内联,但在某些情况下,它需要内联关键字的存在注意:我在这里只谈论后者编译器只有在看到inline关键字时才会内联任何函数。换句话说,如果.cpp有以下代码:
A类;A.my_inline_method();
如果在编译此cpp文件时,my_inline_method()作为内联函数对编译器不可见,则它将不会内联此函数。
- 当涉及到编译时,模板类似于内联方法——当模板的代码需要由编译器在使用它的.cpp中生成时——它需要知道该模板的整个实现。由于模板代码生成是编译时和NOT运行时生成的
我已经提到了这背后更常见的哲学。如果我错过了,请随意编辑此答案以添加更多内容。
关于模板的更多信息:为什么模板只能在头文件中实现?
编辑:根据@Forever的评论进行了更改,以避免歧义。
我在回答自己的问题时补充说,模板实现的一个标准扩展似乎是.tcc
。它被github的语法高亮器识别,也在gcc
手册页中提到:
C++源文件通常使用后缀
.C
、.cc
、.cpp
、.CPP
、.c++
、.cp
或.cxx
中的一个;C++头文件通常使用.hh
、.hpp
、.H
、或(对于共享模板代码).tcc
;
如果我误解了.tcc
扩展的预期用途,请告诉我,我会删除这个答案!
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 有没有一种方法可以在编译时获得作用域类名
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 一种在C++中读取TXT配置文件的简单方法
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 在调用接收数组的方法时,模板化数组大小是不是一种糟糕的做法
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 将错误返回给调用方而不是立即在 C++ 中抛出错误是否是一种好的做法
- cpp 中是否存在一种数据结构,可以轻松地提供一种基于已存在的实例构建新结构的方法
- 使用GCOV时,是否有一种方法可以避免使用CPP文件中包含的标头文件进行仪器
- 在main.cpp中而不是在头文件中定义函数是不是一种糟糕的做法
- #include.cpp模板实现文件是一种不好的做法吗?
- 一种使C++代码划分为.h和.cpp文件对程序员透明的工具
- 在 CPP 文件中使用命名空间作为函数定义的前缀是否是一种好的做法
- 是否有一种方法可以将一个条件设置为gdb中的所有断点,用于调试Cpp代码