5

バックグラウンド

次のような抽象クラスがあります

class IConverter{
    public:
    virtual void DoConvertion() = 0;
};

DoConversionメソッドを実装するだけの多くの具体的なクラスがあります。

class TextConverter : public IConverter{
    public:
    virtual void DoConvertion(){
         // my code goes here
     }
};

class ImageConverter : public IConverter{
    public:
    virtual void DoConvertion(){
         // my code goes here
     }
};

このような多くの具体的な実装があります。抽象クラスIConverterを持つCharacterConverter.hなどのヘッダー ファイルを作成しました。

質問

私の具象クラスはDoConversionメソッドを実装するだけなので、具象クラスごとに個別のヘッダー ファイルを作成する必要がありますか? つまり、すべての具象クラスに対してImageConverter.hTextConverter.hなどを作成する必要があるということですか? これらすべてのヘッダー ファイルには、IConverter抽象クラスのような同じコードが含まれます。

何かご意見は?

4

7 に答える 7

8

必須ではありません。基本的には裁判です。

各クラスの実装が単純な場合は、それらすべてを 1 つの .h と 1 つの .cpp に入れることができます

実装がもう少し長い場合は、それぞれに個別の .h および .cpp ファイルを使用する方がおそらくクリーンです。

クラスごとに異なる .h/.cpp を使用する利点:

  • コードを整理してきれいに保ちます
  • コンパイル作業の削減: 実装の 1 つを変更しても、他のすべてを再コンパイルする必要はありません。
  • コンパイル時間の短縮: Visual Studio の /MP スイッチなど、複数のファイルを一度にコンパイルできるコンパイラがいくつかあります。複数のファイルを使用すると、コンパイル時間が短縮されます。
  • 他のファイルには、すべてではなく、必要なものだけを含めることができます
  • リンク時間の高速化: インクリメンタル リンクにより、リンク時間が短縮されます。
  • バージョン管理を使用すると、特定の派生クラスの 1 つの変更を見つけるために、大量の 1 つの .h/.cpp ファイルに加えられたすべての変更を調べる代わりに、特定の派生クラスへの変更のみを振り返ることができます。
于 2009-02-18T01:44:24.203 に答える
2

インターフェイス クラスを作成する主なポイントの 1 つは、クライアントが具体的な実装ではなく抽象インターフェイスに依存できるようにすることです。これにより、クライアントに影響を与えることなく実装を自由に変更できます。

インターフェイス宣言と同じヘッダー ファイルに具象宣言を配置すると、これが無効になるため、具象クラスの実装の詳細を変更した場合、クライアントは再コンパイルする必要があります。

于 2009-02-18T04:04:09.437 に答える
1

オブジェクトを作成するには具象クラスの定義が必要になるため、それらの定義を .h ファイルのどこかに配置する必要があります。それらをどのファイルに入れるかはあなた次第です。

于 2009-02-18T02:04:58.023 に答える
1

これに対する最良の答えは、どちらが読みやすいかです。1 つの長いソース ファイルは、あなたや他のプログラマーが理解するのが難しいでしょう。一方、多くの小さな (半分の画面いっぱいの) ソース ファイルも同様に悪いものです。

于 2009-02-18T02:13:29.297 に答える
1

設計の残りの部分に応じて、検討する可能性のあるものは、抽象クラスに適切なサブクラスを構築し、それを IConverter* として返す静的メソッド (または実装方法に応じて複数の静的メソッド) があるファクトリです。 . これにより、ヘッダー ファイルで抽象定義のみを公開し、すべての具体的なクラスの定義と実装をスーパー クラスの実装と共に 1 つの .cpp ファイルに含めることができます。サブクラスが大きい場合、これは少し扱いに​​くくなりますが、小さいクラスでは、管理する必要があるファイルの数が減ります。

しかし、他の人が指摘しているように、最終的には判断の呼びかけです。唯一のパフォーマンスの問題は、コンパイルに関連しています。cpp ファイルが増えるとコンパイルに (わずかに) 時間がかかり、ヘッダー ファイルが増えると依存関係の分析が増える可能性があります。ただし、すべてのヘッダー ファイルに一致する cpp とその逆があるという要件はありません。

コメントに基づいて、次のような構造をお勧めします。

IConverter.h ==> IConverter
Converters.h の定義 ==> すべてのサブクラスの定義
IConverter.cpp ==> IConverter.h と Converters.h を含み、IConverter 抽象機能 (静的ファクトリ メソッドと継承可能な機能) の実装を含む
TextConvter .cpp、ImagerConverter.cpp など ==> サブクラスごとに個別の cpp ファイル。それぞれに IConverter.h と Converters.h が含まれます。

これにより、ファクトリおよび汎用機能を使用するクライアントにのみ IConverter.h を含めることができます。他のすべての定義を 1 つのヘッダーに入れると、それらがすべて基本的に同じである場合に統合できます。個別の cpp ファイルを使用すると、Brian が言及したコンパイラの利点を利用できます。前述のようにヘッダー ファイルのサブクラス定義をインライン化することもできますが、実際には何も得られません。インラインのような最適化に関しては、コンパイラは通常、あなたよりも賢いです。

于 2009-02-18T02:16:00.570 に答える
1

おそらく両方の方法で答えが得られます。

些細なコンバーターの場合、それらすべてを単一の .h/.cpp ペアにするだけで十分であり、すべてを単一のペアに分割するのはやり過ぎだと思います。この場合、多数のファイルのメンテナンスと単一のファイル内の一連のメソッドのメンテナンスのトレードオフは価値があると思います。

複雑な変換には、おそらく独自のファイル ペアが必要です。

于 2009-02-18T01:42:26.610 に答える
1

おそらく、ファクトリまたは関数ポインターを使用する方がよいでしょう。

ただし、具体的なクラスを宣言するためにマクロを使用するという、特に厄介な方法が思い浮かびます。例えば:

IConverter.h の下部に、次のマクロを含めます。

#define DECLARE_CONVERTER_CLASS(CLASS_NAME) \
class CLASS_NAME : public IConverter\
{ \
    public: \
    CLASS_NAME() {} \
    virtual void DoConversion(); \
}; \

次に MyConverter1.cpp で

DECLARE_CONVERTER_CLASS(MyConverter1)

virtual void MyConverter1::DoConversion()
{
    ...
}

うん:-)

于 2009-02-18T10:46:38.283 に答える