2016-06-09 104 views
2

我正在使用C++编写一个大项目。把同一个类的方法实现放在不同的目标文件中

我有许多类具有完全不同的事情的方法(如一个转储,另一个修改对象,另一个检查它是否有效等)。

将源文件(或可归档的一组对象文件)中的所有类的方法的实现以及另一个类的另一个方法的实现归档?

当链接时,这可能是好的,也许有人不需要转储方法(例如),或者最好是保持同一个源文件中同一类的方法实现,以免混淆?

+0

每个类都在头文件中声明,与头文件本身有关。然后在相关的源文件中有与该对象本身有关的方法的实现(如你所说的,getter,setter,ctors/dtors ...)。然后其他方法(在几乎整个类层次中被覆盖)在项目的完全分离部分中实现。 – NoImaginationGuy

+0

如果您从目标文件创建存档,链接器将只选择那些需要的目标文件,但请注意,如果它决定选择某个目标文件,则将包含整个目标文件,而不仅仅是需要的部分,所以我认为最好将多个对象文件中的功能分开,然后从中创建存档。 – PcAF

回答

4

有一些权衡。

当您更改任何函数的实现时,必须将整个翻译单元重新编译为新的目标文件。

如果您只为每个翻译单元编写一个函数,那么可以最大限度地缩短由不必要的重建导致的编译时间长度。另一方面,为每个翻译单元编写单个函数,可以使编译时间从头开始最大化,因为编译许多小TU比编译TU要慢。

最佳解决方案是个人喜好,但通常在“每个TU单个功能”和“整个程序的一个大量TU”(而不是其中的一个)之间。对于会员功能,每个班的一个TU是一种流行的启发式方法,但不一定总是最好的选择。


另一个考虑因素是优化。对非内联函数的调用可以内联扩展,但只能在同一个翻译单元内进行扩展。因此,编译器更容易优化单个大规模TU。

当然,您可以选择在头文件中内联定义函数,但这会导致重建问题,因为如果任何内联函数发生更改,则包含头的所有人都必须重新构建。这比仅仅拥有更大的TU更糟糕的问题,但并不像拥有一个巨大的TU那样糟糕。

因此,在同一TU中定义相关的非内联函数允许编译器决定该TU内的优化,同时防止重建级联。如果这些相关功能可以从内联扩展中获益,并且互相呼叫很多,这将是有利的。

该优点通过整个程序优化来减轻。


第三个考虑是组织。看起来类的成员函数的程序员可能也会对该类的其他成员函数感兴趣。让他们在同一个源文件中可以让他们花更少的时间搜索正确的文件。

将所有类功能分组为一个通用源文件的组织优势可以通过现代IDE缓解,这些IDE允许从源文件快速跳转到标题并从那里跳转到其他功能。


第四个考虑因素是编辑的表现。解析数以万计的行或更多的文件可能会很慢,并可能会使用大量的内存,具体取决于解析技术。一个巨大的TU并不一定会导致这种情况,因为您可以使用仅包含在一起的单独文件。

另一方面,大量文件对于某些文件浏览器(可能不是很多)以及版本控制系统可能会产生问题。


最后,我认为:我认为每个类的一个源文件是一个体面的启发式。但是当它不合适时,不应该遵循宗教信仰。

+0

是的!问题更多的是关于项目管理的总体而不是编制效率。由于函数不会经常发生变化,因此就我而言,编译速度方面,大量的TU会更好。 – NoImaginationGuy

+0

@ osnapitzkindle如果函数没有改变,那么你根本不需要编译。如果单个函数发生变化,那么大量的TU将导致整个程序重新编译,而单个函数在TU之前将只允许重新编译一个函数。我得出了相反的结论。 – user2079303

1

一些组织的规则要求每个单元有一个定义。在这些组织中,头文件只能定义一个类,而翻译单元只能定义一个函数。其他组织至多为每个头文件指定一个源文件(某些头文件没有实现)。

要做的最好的事情是介于两者之间。我通常不关心编译器或链接器的性能。我关心代码的可读性和可维护性。实现几千行长的类的源文件很难浏览。最好将该文件分解成多个文件。将其分解为数百个文件,每个函数一个文件,使得目录结构难以导航。将其分解成密切相关的函数块,可以保持目录结构和每个文件的内容可导航。

然而,这是一个很大的问题:为什么你的班级如此之大以至于你不得不担心这个问题?一个实现跨越数千行或数十个文件的类是一种代码异味。

相关问题