2

そのクラスが多数のプライベート定数を定義しているときに、クラス宣言内から別のファイルを #include してはならない理由はありますか?

単純な状態遷移システムに準拠し、それぞれが一連のステップで構成される複数の状態からなる処理スケジュールを定義するクラスを作成しています。クラスはさまざまな関数でこれらの状態とステップを参照する必要があるため (たとえば、現在の状態とステップに基づいて適用する処理を決定する場合)、実装を行うためにクラスの宣言内で一連のプライベート列挙型を定義することになります。読み取り可能です (したがって、これらの状態とステップに関連付けられた生の整数値を使用するだけでなく、kStates_ModeTransition や kStateSteps_ModeTransition_PrepareNewSetup などを参照できます)。

状態と状態ステップのリストが長くなるにつれて、この列挙型のコレクションは、クラス宣言の途中でかなり長くてぎこちないコードの塊になりました。これらの定数は、インターフェイスよりも実装に関連しているように感じます-クラスのユーザーは、必ずしもそれらについて知る必要はありません。これらの列挙型をすべて別のファイルに移動してから、そのファイルをクラス宣言のプライベート セクションに #include するべきではない理由はありますか? クラスの本体内で #include を使用することが適切であると思われる別の状況に遭遇したことはないので、これを処理するより良い方法があるかどうか、またはそのような #include が悪い形式になる特定の理由があるかどうか疑問に思っています。さらに、そのようなファイルで使用する適切な標準ファイル拡張子はありますか? テキスト挿入にのみ使用されます (実際にはヘッダーではありません...)? .txtだけですか?

ありがとう!

編集:言及された代替手段の1つが私のジレンマを完全に解決するかどうかを確認するためにもう少し:

本質だけに固執しようとしている、これが私の現在の構造の例です

// 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() は、オブジェクトの現在の状態と状態ステップに基づいて、特定の処理機能と IO を実行する switch ステートメントで構成されます。

列挙型で宣言された値は、Process() および processor.cpp 内の他のプライベート メンバー関数内で使用され、それ以外の場所では使用されません。クラス内にスコープを設定するために、これらをプライベート メンバー変数として宣言しました。それらを .cpp 内で宣言し、同じスコープを達成する方法はありますか? これらはすべて、コンパイル時に最適化された定数整数であることを意図しており、本質的に #define として使用されています - 私はマクロを使いたくないだけです。

4

4 に答える 4

1

すべてのインクルードは単なるテキストのインクルードです。インクルードするファイルには C++ 構文が含まれているため、C++ ヘッダー拡張子 (.h または .hpp など) が必要です。

それを宣言に含める必要はないかもしれません(コードを投稿すれば、これについてより確実に話すことができます)...実装ファイルに含めるだけで、列挙型メンバー変数を次のように宣言できますint... typedefsを使用して(int説明的な型名を付けたい場合は、) のエイリアス。または、C++11 を使用している場合は、列挙型を定義せずに前方宣言することができます。これにより、列挙型メンバー変数がタイプセーフになり、間違った種類の列挙値の割り当てが防止されます。

列挙型をクラス宣言から別のファイルに移動してそのファイルをインクルードしてはならない理由があるかどうかという質問については、次のように、何かをしない理由をいつでも発明できます。最上位以外のファイル、ファイルの先頭にある」と述べていますが、そのような恣意的な理由があなたに当てはまらない場合は、いいえ、理由はありません。コードの保守性に関して最も理にかなっていることを行います。

于 2013-02-28T04:14:37.103 に答える
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...
    };
};

この構造がこの特定のユースケースに最適であると私が考える理由は次のとおりです。

  1. すべての列挙型リストは、必要に応じてヘッダーの中央から .cpp ファイルに移動され、同じ値を含む追加の StateStep 列挙型 (たとえば、0 からのカウントアップ) を、邪魔することなく StateSteps 構造体の定義に追加できます。 .h ヘッダー ( forward-declared にエントリを追加することはできますenum classが、同じ値を繰り返すことはできずenum class、ヘッダーに別の値を追加する必要があります)。

  2. すべての列挙型は、以前と同様にクラスのプライベート部分内にスコープされます (ただし、別の構造体内でも)。

  3. コンパイル時の整数定数を定義するために使用されている列挙型は、匿名のままであり、厳密に型指定されたenum class構造ではない可能性があります。これにより、列挙型がどのように使用されているかについて他の人に誤解を与える可能性があります (現在のユースケースでは、異なる状態を比較できるようにしたいです)currentStep最初に定義された匿名の列挙型で可能だったように、現在の状態に応じて、列挙型の値を同じ整数に変換します)。

以前の回答がこの結論にたどり着くのに役立ちましたが、これは元の定義の機能を最も厳密に複製し、.h ファイルから移動する方法だと思います。

于 2013-03-01T00:20:30.470 に答える
0

新しい C++11enum 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;
} 
于 2013-02-28T06:06:14.743 に答える
0

クラスの途中でを使用する#includeことは非常に不規則であり、問​​題を引き起こす可能性があります。独自の名前空間またはクラスで定数を宣言する方がはるかに優れています。

たとえば、これは悪い考えです。

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

より典型的なパターンは次のとおりです。

#include "foostuff.h"

class Foo
{
   void bar(int x = FooStuff::const_x);
};

内部foostuff.hでは、名前空間に注意して、アプリケーションの他の部分と衝突しないようにします。

C++ の方法では、アプリケーションのさまざまな部分間で定数を再利用することが推奨されます。マクロを使用#defineして、一度展開すると特定の関連性がないマクロを作成するのではありません。

すべての「インクルード」ファイルは.h、プレーン C.hpp用か、解釈に C++ 対応コンパイラを必要とするもの用のいずれかである必要があります。それ以外のものはすべて非標準であり、少なくとも、コードを維持しなければならない人からの軽蔑につながります。

于 2013-02-28T04:21:50.263 に答える