当该类定义了许多私有常量时,是否有任何理由不应该在类声明中#include另一个文件?
我正在编写一个遵循简单状态转换系统的类,并定义一个由多个状态组成的处理计划,每个状态由一系列步骤组成。因为类必须在各种函数中引用这些状态和步骤(例如,在根据当前状态和步骤确定要应用哪些处理时),我最终在类的声明中定义了一堆私有枚举来实现可读(因此我可以参考诸如kStates_ModeTransition和kStateSteps_ModeTransition_PrepareNewSetup等内容,而不仅仅是使用与这些状态和步骤相关联的原始整数值)。
随着状态和状态步骤的列表变得越来越长,这个枚举的集合在类声明的中间变成了一个相当长的,笨拙的代码块,我觉得这些常量与实现的关系比接口 - 类的用户不一定要了解它们。有什么理由我不应该将所有这些枚举移动到另一个文件然后#include该文件到类声明的私有部分?我没有遇到另一种情况,在类的主体中使用#include似乎是合适的,所以我想知道是否有更好的方法来处理这个或任何特殊的原因,这样的#include会是糟糕的形式。此外,是否有任何明智的标准文件扩展名用于此类文件,仅用于文本插入(它不是真正的标题......)?只是.txt?
谢谢!
编辑:再看看上面提到的替代方案之一是否完全消除了我的困境:
试图只关注要领,这是我当前结构的一个例子
// Processor.h
class Processor
{
public:
Processor();
void Process( float* input, float* output, int numSamples );
private:
// List of possible states
enum
{
kStates_Default,
kStates_SettingChangeImmediate,
kStates_SettingChangeCrossfade,
kStates_SpecialProcessing,
kStates_NumStates
};
// Lists of steps for each state...
enum
{
kStateSteps_Default_PrepareInput,
kStateSteps_Default_CalculateIntermediateValues,
kStateSteps_Default_CalculateOutput,
kStateSteps_Default_NumSteps
};
// Imagine more lists for other states here, with comments...
// Becoming quite long...
// Private functions used in implementing various processing steps
// (some are used by multiple state-steps in varying ways)
void PrivateFunction1();
void PrivateFunction2();
// Some member variables here
};
这用于实时处理上下文,以便在执行块处理任务时更好地平衡DSP负载。实际上,此类继承自基类,该基类处理对Process的调用的实际调度,根据需要更新当前状态和状态步骤。然后,Process()包含一个switch语句,它根据对象的当前状态和状态步骤执行某些处理函数和IO。
在枚举中声明的值在Process()和processor.cpp内的其他私有成员函数中使用,而不是在其他地方使用。我已经将它们声明为私有成员变量,以将它们扩展到类中。有没有办法在.cpp中声明它们并实现相同的范围?这些都是在编译时优化掉的常量整数,基本上用作#define - 我只是不想使用宏。
答案 0 :(得分:1)
所有包含只是文字包含。由于您所包含的文件包含C ++语法,因此它应具有C ++标头扩展名(.h或.hpp等)。
您可能不需要将它包含在声明中(如果您发布一些代码,我可以更肯定地说出来)...您可以将它包含在实现文件中,并将任何枚举成员变量声明为{{1如果要为它们提供描述性类型名称,请使用typedef(int
的别名)。或者如果你正在使用C ++ 11,你可以转发声明你的枚举类型而不定义它们,然后你枚举成员变量将是类型安全的,防止分配错误的枚举值。
关于你是否有理由不将你的类声明中的枚举移到另一个文件中并包含该文件的问题:人们总是可以发明不做事情的理由,例如“我们的编码标准说”永远不要在文件顶部包含顶级以外的文件,“但是如果这些任意的理由不适用于你那么没有,那就没有理由了。在代码可维护性方面做最有意义的事情。
答案 1 :(得分:0)
在课程中间使用#include
是非常不规则的,可能会导致问题。如果在自己的命名空间或类中声明常量,那就更好了。
例如,这是个坏主意:
class Foo
{
#include "foostuff.h"
};
更典型的模式是:
#include "foostuff.h"
class Foo
{
void bar(int x = FooStuff::const_x);
};
在foostuff.h
内,你要小心命名,这样它们就不会与应用程序的其他部分发生碰撞。
C ++的做事方式鼓励在应用程序的不同部分之间重用常量,而不是使用#define
创建宏,一旦扩展,就没有特定的关联。
所有“include”文件对于普通C应该是.h
,对于需要C ++兼容编译器来解释的任何文件都应该是.hpp
。其他任何事情都是非标准的,至少会导致任何必须维护你的代码的人嗤之以鼻。
答案 2 :(得分:0)
可以向前声明新C ++ 11 enum class
,并将实际定义移至实现。这将清理混乱并减少烦恼。
// Procesor.hpp
class Processor
{
public:
Processor();
void Process( float* input, float* output, int numSamples );
private:
// Type of possible states
enum class kState;
kState somethingDealingWithState( kState s );
};
// Processor.cpp
// List of possible states
enum class Processor::kState
{
Default,
SettingChangeImmediate,
SettingChangeCrossfade,
SpecialProcessing,
NumStates
};
Processor::kState Processor::somethingDealingWithState( kState s )
{
if ( s == kState::Default )
{
return kState::SpecialProcessing;
}
return kState::Default;
}
答案 3 :(得分:0)
最后,似乎是获得等效功能的最佳方法,同时获得将枚举细节分离到.cpp实现文件中的好处是在类的私有部分中使用结构的前向声明,并且然后定义该结构以包含.cpp文件中所需的枚举。
// Processor.h
class Processor
{
public:
Processor();
void Process( float* input, float* output, int numSamples );
private:
struct States; // Used to scope State enum to within class
struct StateSteps; // Used to scope StateStep enums to within class
// Other stuff...
}
// Processor.cpp
struct Processor::States
{
enum
{
Default,
SettingChangeImmediate,
SettingChangeCrossfade,
SpecialProcessing,
NumStates
};
}
struct Processor::StateSteps
{
enum
{
Default_PrepareInput,
Default_CalculateIntermediateValues,
Default_CalculateOutput,
Default_NumSteps
};
enum
{
SettingChangeImmediate_FirstStep,
// ... other state-steps...
};
};
这就是我认为这种结构在这个特定用例中最好的原因:
所有枚举列表都会根据需要移出到标题中间的.cpp文件中,并且可以在定义中添加包含相同值(例如,从0开始计数)的其他StateStep枚举在不打扰.h标头的情况下StateSteps结构(虽然我们可以向前向声明的enum class
添加条目,但我们不能重复相同的值,并且需要向其添加另一个enum class
头)。
所有枚举都像以前一样在类的私有部分范围内(尽管在另一个结构中也是如此)。
用于定义编译时整数常量的枚举可以保持匿名而不是强类型enum class
构造,这可能会误导其他人如何使用枚举(在当前使用中 - case,我们希望能够将不同的stateStep枚举值与同一个整数currentStep
进行比较,具体取决于当前状态,就像我们最初定义的匿名枚举一样。)
以前的答案帮助我得出了这个结论,但我觉得这是一种最接近原始定义功能的方式,同时将它们移出.h文件!