将包含大量类的一个文件转换为每个文件一个类的许多文件

时间:2010-03-13 08:50:31

标签: c++ refactoring

如何将包含大量类的一个文件转换为每个文件一个类的多个文件? (C \ C ++)

所以我有这样的结构的文件:有些包括,然后很多有时互相调用的类:

#include <wchar.h>
#include <stdlib.h>
//...
class PG_1 {
  //...
}
class PG_2 {
  //...
}
//......
class PG_N {
  //...
}

7 个答案:

答案 0 :(得分:4)

如果您没有使用版本控制(tsk tsk):

  1. 备份整个项目以防万一陷入困境。
  2. 将每个类剪切并粘贴到自己的classname.hclassname.cpp文件中。将classname替换为类的名称。更新包含警卫。
  3. 添加您认为每个类的依赖项所必需的#include指令。
  4. 删除multiclass.hmulticlass.cpp
  5. 将单类文件添加到项目或makefile中。从项目或makefile中删除多类文件。
  6. 构建项目或makefile。
  7. 如果无法构建,请修复问题(例如缺少#include)并转到步骤6.
  8. 构建完成后,运行测试。
  9. 如果测试失败,请诊断并解决问题,然后转到步骤6.
  10. 如果您使用的是支持文件级分支的修订控制系统(例如Perforce,或者Subversion?),您应该注意保留修订历史记录,以便其他开发人员可以找到旧的更改:

    1. 在开发分支中执行其余步骤,而不是主干。
    2. 对于multiclass.hmulticlass.cpp中的每个班级名称,请将multiclass.hmulticlass.cpp整合到该班级的单独classname.hclassname.cpp中。
    3. 提交包含所有这些集成的更改列表。这将生成原始文件的N个副本,并且它们都具有指向原始文件的修订历史记录。
    4. 检查每个新文件以进行编辑。
    5. 从每个新文件中删除除该特定类所需的代码之外的所有内容,并更新包含警卫。
    6. 添加您认为每个类的依赖项所必需的#include指令。
    7. 检查旧版multiclass.hmulticlass.cpp是否已删除。
    8. 查看项目或makefile以进行编辑。
    9. 将单类文件添加到项目或makefile中。从项目或makefile中删除多类文件。
    10. 构建项目或makefile。
    11. 如果无法构建,请解决问题(例如缺少#include)并转到步骤10.
    12. 构建完成后,运行测试。
    13. 如果测试失败,请诊断并解决问题,然后转到步骤10.
    14. 提交包含所有修改的更改列表。
    15. 如果您使用的是不支持文件级分支的修订控制系统,那么这两种方法的某些组合应该可以使用。希望你明白了。

答案 1 :(得分:2)

  

如何使用大量文件来翻转一个文件   具有一个类的许多文件的类   每个文件?

编辑:关于一般的重构,我应该提一下。重构中没有重要的一步(除非你想破坏你的代码库)。您应始终对代码进行事务转换,并在其间进行有效性检查(事务性意味着它们明确分隔,并且可以在任何时候提交和回滚)。如果你有很大的步骤意味着你没有将它们分解成小步骤。此外,每一步都应该做一件事,一件事。 (结束编辑)。

步骤:

  1. 备份所有内容(所有受影响的文件)

    这意味着在源代码管理系统中执行提交。如果您不使用任何源代码控制,请在继续之前安装mercurial(继续,我们将等待;)) - 您可以稍后再次感谢我:D

  2. 为要删除的第一个类创建新文件(.h和.cpp文件),然后在旧标题中包含新的.h文件(具有多个类的文件)。

    < / LI>
  3. 移动.h文件中的类声明和新.cpp文件中的类实现。

  4. 从旧文件中删除声明/实现。此时编译代码,并将#include dirrectives从旧文件复制到新文件,直到所有内容编译。此时,您应该将您的类移动到单独的文件,并包含在旧的头文件中。不要复制所有包含,只能让您移动的类正确编译。

  5. 编译代码(最终运行应用程序并确保一切运行)。

  6. 在源代码管理系统中执行提交。

  7. 从旧(多个类)头文件中删除包含的新文件并进行编译。浏览代码并将新文件包含在您收到错误的任何文件中。

  8. 重复步骤5和6.

  9. 选择新课程,返回第1步。

  10. 可能出现的错误和警告:

    • 您可能会在将新代码移动到新文件时对其进行其他更改。 不做任何更改。在循环结束时(在步骤8之后),您应该具有与步骤1之前相同的代码,只需在不同的文件中。您在步骤之间对代码所做的任何更改将难以与重构分离,以后难以跟踪且难以反转。这不值得麻烦,特别是当重构周期完成后你可以做出相同的改变(没有其他问题)。

    • 您可能想要同时处理多个课程。不要这样做。如果您在循环中工作,您始终可以将代码(在SCM中)还原为有效的代码版本,并且您可以进行模块化更改。如果你一次上一堂课,也可以很容易地跟踪变化并检查你是否没有引入新的错误。

    Sidenote :如果您使用分支SCM,您将能够并行处理任务,中断您的重构(提交所有内容 - 让我们称之为“分支头A”),返回在开始重构之前的代码,进行一些其他更改,提交它们(称之为“分支头B”),然后返回分支头A,完成重构,然后合并A和B,你就可以了。< / p>

答案 2 :(得分:1)

有几种方法可以实现这一目标。

最直接的方法是一次读取一行文件并检测该行是否开始上课。

然后开始检测匹配的括号...你知道如果你找到{ +1和} -1,直到你达到零。是的,还有更多,但这是主要部分。

选择该块并将其写入另一个文件。

另一方面, IF 你正在使用Visual Studio,就是创建一个宏并使用DTE来仔细阅读当前打开文件的FileCodeModel ,并为其中的每个顶级类创建一个文件。

答案 3 :(得分:0)

你知道如何手动完成吗?如果你知道,编写一个程序来做同样的事情是很简单的。

答案 4 :(得分:0)

可能没有简单的方法可以做到这一点。问题是你必须让#include正确,将代码正确地拆分到不同的头文件和cpp文件,如果你的类之间有循环依赖关系,你必须正确处理它们,或者更好,尝试解决这些依赖关系,使它们成为非循环的。

最佳建议我可以给你:首先尝试手动完成两到三节课。然后决定你需要什么样的物理类布局。然后,尝试编写程序。除非你完全明白该做什么,否则不要尝试编写程序。

顺便说一下,有多少个类/文件?

编辑:为了更好地了解良好的物理类到文件布局可能是什么,我建议阅读John Lakos的Large Scale C++ Design。有点过时,因为它不包含任何有关预编译头文件的内容,但仍然有用。

答案 5 :(得分:0)

两种基本的编码风格模式是可能的:

  1. 标题中的类声明,.cpp文件中的成员函数/静态数据实例化。
  2. 在标题中使用内联实现的类定义
  3. 选项2可能会导致代码膨胀,因为如果您在多个编译单元中使用该类,您可能会在最终链接中获得多个实现副本;它取决于联系人根除这一点,它可能会也可能不会这样做 - YMMV。它还允许类的用户访问实现,这在某些情况下可能是不合需要的。

    两者结合使用简单的getter / setter函数内联和单独编译单元中的较大代码体是一种选择。通常如果我有一个完全由初始化列表实现的构造函数,我会将其空体包含在内。

    班级cExampleClass的示例:

    <强> cExampleClass.h

    class cExampleClass
    {
    public:
        cExampleClass() ;
        ~cExampleClass() ;
        void memberfn() ;
    } ;
    

    <强> cExampleClass.cpp

    cExampleClass::cExampleClass() 
    {
        // body
    }
    
    cExampleClass::~cExampleClass()
    {
        // body
    }
    
    void cExampleClass::memberfn()
    {
        // body
    }
    

    或内联:

    <强> cExampleClass.h

    class cExampleClass
    {
    public:
        cExampleClass()
        {
            // body
        }
    
        ~cExampleClass()
        {
            // body
        }
    
        void memberfn()
        {
            // body
        }
    } ;
    

    在这两种情况下,任何使用cExampleClass的源文件都只包含cExampleClass.h,而cExampleClass.cpp(如果存在)则单独编译和链接。

    请注意,如果类包含静态数据成员变量,则必须在单独的编译单元中实例化这些 ,以便只有一个公共实例。例如:

    <强> cExampleClass.h

    class cExampleClass
    {
    public :
        static int staticmember ;
    } ;
    

    <强> cExampleClass.cpp

    int cExampleClass::staticmember = 0xffff ;
    

答案 6 :(得分:0)

我建议编写一个脚本(使用您最喜欢的脚本语言)将类声明提取到自己的文件中。如果你不擅长脚本语言,你总是可以编写一个C ++程序来提取类声明。

另一种可能性是使用具有重构功能的IDE或重构应用程序。我从未使用过这些,所以我不能就他们的能力提出建议。