11

私はC++にかなり慣れていませんが、#includeステートメントは基本的に#includedファイルの内容をそのステートメントの場所にダンプするだけであると理解しています。つまり、ヘッダーファイルに多数の「#include」および「using」ステートメントがある場合、実装ファイルはヘッダーファイルを#includeするだけで済み、コンパイラは他のステートメントを繰り返さなくてもかまいません。 。

でも人はどうですか?

私の主な懸念は、「#include」、「using」、および「typedef」(今では考えている)ステートメントを繰り返さないと、その情報が使用されているファイルから削除されることです。混乱を招く可能性があります。

小さなプロジェクトに取り組んでいて、実際には何の問題も起こらないのですが、より多くの人が取り組んでいる大きなプロジェクトでは、それが重大な問題になる可能性があると想像できます。

次に例を示します。

更新:「Unit」の関数プロトタイプには、戻り型とパラメーターの中にstring、ostream、StringSetが含まれています-実装ファイルでのみ使用されるヘッダーファイルには何も含めていません。

//Unit.h

#include <string>
#include <ostream>
#include "StringSet.h"

using std::string;
using std::ostream;

class Unit {

public:
    //public members with string, ostream and StringSet
    //in their return values/parameter lists
private:
    //private members
    //unrelated side-question: should private members
    //even be included in the header file?
} ;


//Unit.cpp

#include "Unit.h"

//The following are all redundant from a compiler perspective:
#include <string>
#include <ostream>
#include "StringSet.h"

using std::string;
using std::ostream;

//implementation goes here
4

5 に答える 5

9

using ディレクティブ( )using namespace std;は、関数内に含まれていない限り、ヘッダーに配置しないでください。それは悪い習慣です。ヘッダーのすべてのユーザーが、特定の名前空間内のすべてに対して非修飾ルックアップを必要とすることはまずありません。無関係なヘッダーを含めると、予期しないあいまいさとコンパイルの失敗につながる可能性があります。個人的には、同じ理由で関数内のusing ディレクティブを避けていますが、これは一般的に害が少ないと考えられています。

エイリアス( または を介し​​てtypedef std::string string;)using string = std::string;は慎重に使用する必要があります。型定義には意味があるため、再宣言しないでください。たとえば、これはエラーです。

typedef int   myint;
typedef float myint;

型が競合するためです。

using 宣言(using std::string;または) は、非修飾名検索using std::memcpy;でシンボルにアクセスできるようにします。ライブラリを作成していない限り、通常は問題にならない、引数に依存するルックアップを正しく取得する場合に非常に役立ちます。型と関数のどちらを持ち込むかによって、アドバイスは異なります。型エイリアスと同じ方法で、型を持つusing-declaration を考えてください。同じ名前で複数の定義を持つことは意味がありません。関数で実際に行っていることは、オーバーロードの解決を拡張して、さらにいくつかのものを含めることだけです (ただし、通常は必要ありません)。

// Finding multiple operator<< functions makes sense
using std::operator<<;
using mylib::operator<<;

// Finding multiple string classes does not make sense
using std::string;
using mylib::string;

繰り返し#includeの場合、最初にヘッダーにファイルを実際に含める必要があるかどうかを検討する必要があります。おそらく、前方宣言がニーズに合っているでしょう。

于 2010-04-26T23:36:23.877 に答える
5
  • 本当に必要なものだけをヘッダー/ソースに含めます(前方宣言が利用可能で十分な場合は、含める代わりに前方宣言します)
  • usingヘッダーでステートメントを使用しないでください(関数スコープ内を除く)...ヘッダーを追加するusingと、ヘッダーを含むすべてのソースの名前空間が汚染されます。
  • 各ファイル(ソースのヘッダー)に必要なものがすべて含まれていることを確認する必要があります。

一部のインクルードが冗長であるかどうかを気にする必要はありません。ヘッダーガードとプリコンパイラの最適化は、それを処理するためにあります。

各ファイルを個別に操作できるはずです。

たとえばstd::string、ヘッダーとソースでを使用するとしますが、「最適化」として、ヘッダーに文字列のみを含めました...後で発見した場合は、ヘッダーに文字列はもう必要ありません、そしてそれを削除したい場合(コードのクリーニング、およびすべて...)、文字列を含めるようにソースを変更する必要があります。ここで、ヘッダーを含む10個のソースがあると想像してみましょう...

もちろん、このルールには例外を設けることができます(たとえば、プリコンパイル済みヘッダー、または礼儀として複数のインクルードを実行することを唯一の目的とするヘッダー)が、デフォルトでは、自給自足のヘッダーファイルとソースファイルが必要です(つまり、使用するものをすべて含むファイル、それ以上でもそれ以下でもありません)。

于 2010-08-06T22:05:00.977 に答える
0

using意図的にシンボルを別の名前空間に複製する場合を除き、ヘッダー ファイルにステートメントを含めることは悪い形式と見なされます。cpp ファイルで使用しても問題ありません。

それぞれtypedefがコードベースに一度だけ存在する必要があります。複数の cpp/h ファイルで使用する必要がある場合は、ヘッダー ファイルに含める必要があります。それらを複製すると、多くの悲しみが生じます。

ヘッダー ファイルには、必要なすべての#includeステートメントが含まれている必要があり、それ以外は含まれていません。クラスへのポインターのみが言及されている場合は、ヘッダーを含めるのではなく、前方宣言を使用してください。cpp ファイル内でのみ必要なその他のインクルードは、そこに移動する必要があります。ヘッダーからインクルードを繰り返すことは問題ありませんが、必須ではありません。それは単なるスタイルの選択です。

于 2010-04-26T23:46:42.100 に答える
0

ヘッダー ファイルは最小限に抑えます。これは、インクルードを可能な限り少なくすることを意味します。.cpp ファイルには通常、対応するヘッダーと、実装に必要なその他のヘッダーが含まれます。

于 2010-04-26T23:41:30.087 に答える
0

Travis が言ったようusingに、ヘッダー ファイルにステートメントを含めるべきではありません。これは、ヘッダー ファイルを含むすべての翻訳単位にステートメントが含まれることを意味し、混乱を招く問題を引き起こす可能性があるためです。

cpp ファイルのヘッダー ファイルの機能のみが必要な場合は、その cpp ファイルにのみ含めます。コンパイラの作業が少なくなるため、大規模なプロジェクトでは良い方法です。また、可能な限り、インクルードの代わりにヘッダーで前方宣言を使用します (また、cpp ファイルにヘッダーを含めます)。

于 2010-04-26T23:43:23.587 に答える