约翰·拉科斯 (John Lakos) 将这个问题称为一个阴险的来源
编译时耦合(图0-3,在他的简介中):
我面临的问题是编译了太多文件,因为对单个枚举存在物理依赖性。
我有一个带有枚举定义的标题:
// version.h
enum Version {
v1 = 1,
v2, v3, v4, v5, ... v100
};
这被数百个文件使用。
每个文件定义一类对象,必须从磁盘读取这些对象,
使用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
}
}
and
// 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);
}
}
现在,正如你所看到的,一旦ObjectA
更改,我们必须引入一个新条目(例如v100
)到Version
。因此所有type*.cpp
文件将被编译,即使只有read()
of ObjectA
确实需要v100
entry.
如何反转对枚举的依赖,并对客户端进行最小的更改(即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
为Version
以某种方式输入
//version.h
typedef const int Version;
并只引入每次需要的 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
}
}
但我认为这看起来是一个非常糟糕的解决方案,可以追溯到标题前的时间