对于c++中大量的私有类常量声明,任何不从另一个文件#include的理由

Any reason not to #include from another file for numerous private class constant declarations in c++?

本文关键字:任何不 另一个 理由 #include 文件 声明 c++ 对于 常量      更新时间:2023-10-16

当类定义了许多私有常量时,是否有任何理由不应该在类声明中包含另一个文件?

我正在写一个类,它遵循一个简单的状态转换系统,并定义了一个由几个状态组成的处理计划,每个状态由一系列步骤组成。因为类来引用这些州和步骤各功能(例如,当确定哪些处理应用基于当前状态和步骤),我最终在类中定义一群私人枚举的声明让实现可读的(所以我可以参考kStates_ModeTransition和kStateSteps_ModeTransition_PrepareNewSetup等等,而不仅仅是使用原始的整数值与这些国家和相关步骤)。

随着状态和状态-步骤列表变得越来越长,枚举的集合在类声明中变成了相当长的、令人尴尬的代码块,我觉得这些常量与实现的联系比与接口的联系更紧密——类的用户不必知道它们。有任何理由为什么我不应该移动所有这些枚举的另一个文件,然后只是#包括该文件到类声明的私有部分?我还没有遇到过在类的主体中使用#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 's -我只是不想使用宏。

所有包含都只是文本包含。因为你包含的文件包含c++语法,所以它应该有一个c++头扩展名(.h或.hpp等)。

你可能不需要将它包含在声明中(如果你发布一些代码,我可以更肯定地说这一点)…你可以将它包含到实现文件中,并将任何枚举成员变量声明为int…如果您想为它们提供描述性类型名称,请使用typedef (int的别名)。或者,如果使用c++ 11,可以在不定义枚举类型的情况下直接声明枚举类型,然后枚举成员变量将是类型安全的,从而防止赋值错误类型的枚举值。

至于你的问题是否有理由你不应该把枚举从你的类声明中移到另一个文件中,并包括那个文件:一个人总是可以发明不做事情的理由,比如"我们的编码标准说永远不要在文件的顶部包括一个文件",但如果这些任意的理由不适用于你,那么不,没有理由。做对代码可维护性最有意义的事情。

在课堂上使用#include是非常不规范的,可能会导致问题。如果在它们自己的命名空间或类中声明常量,效果会好得多。

例如,这是一个坏主意:

class Foo
{
   #include "foostuff.h"
};

更典型的模式是:

#include "foostuff.h"
class Foo
{
   void bar(int x = FooStuff::const_x);
};

foostuff.h中,你要小心命名空间,这样它们就不会与应用程序的其他部分冲突。

c++的工作方式鼓励在应用程序的不同部分之间重用常量,而不是使用#define来创建宏,这些宏一旦展开,就没有特别的关联。

所有的"include"文件应该是.h对于普通C或.hpp对于任何需要c++编译器解释。其他任何东西都是非标准的,至少会导致维护代码的人的嘲笑。

新的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;
} 

最后,在获得将枚举细节分离到.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...
    };
};

以下是我认为这种结构在这个特殊用例中最好的原因:

  1. 所有枚举列表都被移到。cpp文件中,根据需要从头文件的中间移出,并且包含相同值(例如,从0开始计数)的其他StateStep枚举可以添加到StateSteps结构体的定义中,而不会干扰。h头文件(虽然我们可以向前声明的enum class添加条目,但我们不能重复相同的值,并且需要在头文件中添加另一个enum class)。

  2. 所有的枚举都像以前一样被限定在类的private部分内(尽管也是在另一个结构体内)。

  3. 用于定义编译时整型常量的枚举可能保持匿名并且不是强类型的enum class结构,这可能会误导其他人如何使用枚举(在当前用例中,我们希望能够根据当前状态将不同的stateStep枚举值与相同的整数currentStep进行比较,就像我们可以使用最初定义的匿名枚举一样)。

前面的答案帮助我得出这个结论,但我觉得这是一种最接近地复制原始定义的功能的方式,同时将它们移出。h文件!

相关文章: