John Lakos 将此问题称为编译时耦合的潜在根源(他的简介中的图 0-3):
我面临的问题是编译了太多文件,因为对单个枚举存在物理依赖性。
我有一个带有枚举定义的标头:
// version.h
enum Version {
v1 = 1,
v2, v3, v4, v5, ... v100
};
Run Code Online (Sandbox Code Playgroud)
这被数百个文件使用。每个文件定义一类对象,必须使用该read()函数从磁盘读取这些对象。Version用于确定读取数据的方式。
每次引入新的类或类成员时,都会将新条目附加到枚举中
// typeA.cpp
#include "version.h"
void read (FILE *f, ObjectA *p, Version v)
{
read_float(f, &p->x);
read_float(f, &p->y);
if (v >= v100) {
read_float(f, &p->z); // after v100 ObjectA becomes a 3D
}
}
Run Code Online (Sandbox Code Playgroud)
和
// typeB.cpp
#include "version.h"
void read (FILE *f, ObjectB *p, Version v)
{
read_float (f, &p->mass);
if (v >= v30) {
read_float (f, &p->velocity);
}
if (v >= v50) {
read_color (f, &p->color);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,正如您所看到的,一旦发生ObjectA更改,我们就必须v100向Version. 因此,type*.cpp即使只有真正需要该条目的文件,所有文件都将read()被ObjectA编译v100。
如何反转对枚举的依赖,对客户端(即type*.cpp)代码进行最小的更改,以便仅编译必要的 .c 文件?
这是我想到的一种可能的解决方案,但我需要一个更好的解决方案:
我想我可以将枚举放在 .cpp 文件中,并int使用相应枚举成员的值公开 s:
//version.cpp
enum eVersion {
ev1 = 1,
ev2, ev3, ev4, ev5, ... ev100
};
const int v1 = ev1;
const int v2 = ev2;
....
const int v100 = ev100; // introduce a new global int for every new entry in the enum
Run Code Online (Sandbox Code Playgroud)
Version以某种方式为类型创建别名
//version.h
typedef const int Version;
Run Code Online (Sandbox Code Playgroud)
并只引入每次需要的 const int 值:
// typeA.cpp
#include "version.h"
extern Version v100; ///// *** will be resolved at link time
void read (FILE *f, ObjectA *p, Version v)
{
read_float(f, &p->x);
read_float(f, &p->y);
if (v >= v100) {
read_float(f, &p->z); // after v100 ObjectA becomes a 3D
}
}
Run Code Online (Sandbox Code Playgroud)
但我认为这看起来是一个非常糟糕的解决方案,可以追溯到标题前的时间
您可以将枚举作为配置数据放置在单独的 .cfg 文件中,然后其他每个源文件都会读取该配置文件。
那么当配置文件改变时,不需要重新编译。
所有其他文件读取/解析配置文件。
这是处理此类信息的经典方法。
注意:配置文件不会包含枚举,而是包含某些格式化数据。
| 归档时间: |
|
| 查看次数: |
251 次 |
| 最近记录: |