在C++;,当我需要使用枚举时,如何避免包含头文件? P>在我的C++头文件中,我尝试使用正向声明(class MyClass),而不是使用包含许多C++代码标准(谷歌C++风格指南)中推荐的类头(包括:
不幸的是,当我引入枚举时,我不能再做正向声明了。像这样:在C++;,当我需要使用枚举时,如何避免包含头文件? P>在我的C++头文件中,我尝试使用正向声明(class MyClass),而不是使用包含许多C++代码标准(谷歌C++风格指南)中推荐的类头(包括:,c++,include,header,dependencies,C++,Include,Header,Dependencies,不幸的是,当我引入枚举时,我不能再做正向声明了。像这样: //// myclass1.hpp //// class MyClass1 { enum MyEnum1 { Enum_A, Enum_B, Enum_C }; }; //// myclass2.hpp //// // I want to avoid this #include "myclass1.hpp" // I'd prefer to do this (forward declarat
//// myclass1.hpp ////
class MyClass1
{
enum MyEnum1
{
Enum_A, Enum_B, Enum_C
};
};
//// myclass2.hpp ////
// I want to avoid this
#include "myclass1.hpp"
// I'd prefer to do this (forward declaration)
class MyClass1;
class MyClass2
{
// This is o.k.: I only need to forward declare MyClass1
MyClass1* ptr;
// This forces me to #include, but I don't want to!
void func( MyClass1::MyEnum1 e );
};
到目前为止,我能想到的最佳解决方案是用成员常量替换枚举:
//// myclass1.hpp ////
MyClass1
{
static const int Enum_A;
static const int Enum_B;
static const int Enum_C;
};
//// myclass1.cpp ////
const int Enum_A = 1;
const int Enum_B = 2;
const int Enum_C = 3;
不过,在这种情况下,解决方案似乎比问题更糟糕
我目前正在浏览大型C++软件设计(LakOS),并用遗留代码(羽毛)有效地完成依赖性破坏技术,但我还没有找到一个好的解决方案。
< P>只有在声明指针时才能使用正向声明。如果要声明非指针变量,则必须包含相关的头文件因为枚举变量不是指针,所以不能使用前向声明。我认为没有替代方案。这很难很好地做到。也许将
enum
s移动到公共头文件将是一个合理的解决方案
编辑:我知道这个问题是为了避免包含头文件,但是没有办法(AFAIK)做到这一点。将枚举移动到一个单独的头文件至少可以最大限度地减少头文件中确实需要包含的内容量。这肯定比问题中提到的疯狂要好 您不能向前声明枚举值,而您的解决方法是在完全疯狂的道路上跨出一步 您是否遇到了由#包括标头导致的任何主要编译速度减慢?如果没有,就把它们包括在内。使用前向声明是而不是“最佳实践”这是一种技巧。我认为(可以证明我是错误的)您不能前向声明内部类型或枚举。您将需要封闭类的定义才能使用枚举
虽然大多数样式指南强制不包括不必要的标题,但在您的情况下,标题是必需的。如果您真的想要避免包含的选项,您可以考虑的是定义类之外的枚举,并包括定义EnUM的头部。 < P>可以使用模板参数来对“一般”枚举类型进行编程。很像这样:
// enum.h
struct MyClass1 { enum e { cE1, cE2, cELast }; };
// algo.h
// precondition: tEnum contains enumerate type e
template< typename tEnum > typename tEnum::e get_second() {
return static_cast<typename tEnum::e>(1);
}
// myclass1.h
// myclass.h
template< typename tClass1 >
class MyClass2
{
tClass1 * ptr;
void func( tClass1::e e );
};
// main.cpp
#include "enum.h"
#include "algo.h"
int main(){ return get_second<Enum>(); }
//enum.h
结构MyClass1{enum e{cE1,cE2,cELast};};
//算法
//前提条件:tEnum包含枚举类型e
模板typename tEnum::e get_second(){
返回静态_-cast(1);
}
//myclass1.h
//myclass.h
模板
类别MyClass2
{
tClass1*ptr;
void func(tClass1::e);
};
//main.cpp
#包括“enum.h”
#包括“algo.h”
int main(){return get_second();}
C++0x可以向前声明。GCC 4.4.0和CodeGear C++Builder 2009支持强类型枚举
有一些类似enum的类,如(建议但从未最终确定和接受)Boost.enum,可从下载。由于Boost.enum是类,因此可以向前声明它们
<>但是,仅仅将枚举放在一个单独的文件(如In)中似乎是最简单、最好的解决方案(除了C++ 0x支持)。C++的标准委员会实际上已经提出了 枚举向前声明。见(pdf)。这肯定是一个很好的功能 如果由于包含头而导致编译速度减慢,另一个选项是使用
int
而不是enum
。这是一种相当不受欢迎的方法,因为它会降低类型安全性。如果采用这种方法,那么我还建议添加代码以编程方式执行边界检查:
// in class1.h
class Class1 {
public:
enum Blah {
kFirstBlah, // this is always first
eOne = kFirstBlah,
...
kLastBlah // this is always last
};
};
// in checks.h
#include <stdexcept>
namespace check {
template <typename T, typename U>
U bounds(U lower, T value, U upper) {
U castValue = static_cast<U>(value);
if (castValue < lower || castValue >= upper) {
throw std::domain_error("check::bounds");
}
return castValue;
}
} // end check namespace
// in class2.h
class Class2 {
public:
void func(int blah);
};
// in class2.cpp
#include "class2.h"
#include "class1.h"
#include "checks.h"
void Class2::func(int blah) {
Class1::Blah blah_;
blah_ = check::bounds(Class1::kFirstBlah, blah, Class1::kLastBlah);
}
//在class1.h中
一班{
公众:
列举{
kFirstBlah,//这总是第一个
eOne=kFirstBlah,
...
克拉斯布拉//这永远是最后一次
};
};
//在支票上
#包括
名称空间检查{
模板
U界限(U下限,T值,U上限){
U castValue=静态_cast(值);
如果(卡斯特值<下限| |卡斯特值>=上限){
抛出std::domain_错误(“check::bounds”);
}
返回值;
}
}//结束检查命名空间
//在2.h班
二级{
公众:
无效函数(int blah);
};
//在class2.cpp中
#包括“class2.h”
#包括“class1.h”
#包括“checks.h”
void类2::func(int blah){
类别1:诸如此类;
布拉赫=检查::边界(Class1::kFirstBlah,布拉赫,Class1::kLastBlah);
}
这不是最漂亮的解决方案,但它确实通过将静态编译提供的一些类型安全性移到运行时代码中来解决了头依赖性问题。我在过去也使用过类似的方法,并发现以这种方式使用的检查
名称空间可以使生成的代码几乎与基于枚举
的代码一样可读,只需很少的努力
需要注意的是,无论您是否采用这种方法,您都必须努力编写异常安全代码,我建议您这样做;) 在报头中转发声明(只要有可能)是一种很好的做法。这减少了依赖性。如果在私有成员的签名中使用内部类,而不是在公共/受保护的方法中,则用户甚至不需要访问定义类型的头文件。。。。续:以PIMPL成语为例。整个想法是,类的用户不知道内部类是如何/是什么。虽然这是一个非常具体的问题,但它也非常生动。我可以做其他的例子,我和尼尔在一起。如果依赖关系能帮助我尽早发现编译器错误,我不想减少依赖关系。尼尔,我不理解你关于前向减速是黑客的说法。如果我有一个文件,其中引用了SomeClass*,但我从未取消引用过它,为什么我要包含该类?如果使用转发声明,则消除依赖关系。如果我不小心取消引用