web-dev-qa-db-ja.com

C ++でインターフェースと実装を編成する方法

ヘッダーファイルの内容とcppファイルの内容に関して、C++にはいくつかの異なるパラダイムがあることがわかりました。私の知る限り、ほとんどの人、特にCのバックグラウンドを持つ人は、次のことを行います。

foo.h

 class foo {
 private:
     int mem;
     int bar();
 public:
     foo();
     foo(const foo&);
     foo& operator=(foo);
     ~foo();
 }

foo.cpp

 #include foo.h
 foo::bar() { return mem; }
 foo::foo() { mem = 42; }
 foo::foo(const foo& f) { mem = f.mem; }
 foo::operator=(foo f) { mem = f.mem; }
 foo::~foo() {}
 int main(int argc, char *argv[]) { foo f; }

ただし、私の講師は通常、次のような初心者にC++を教えます。

foo.h

 class foo {
 private:
     int mem;
     int bar() { return mem; }
 public:
     foo() { mem = 42; }
     foo(const foo& f) { mem = f.mem; }
     foo& operator=(foo f) { mem = f.mem; }
     ~foo() {}
 }

foo.cpp

 #include foo.h
 int main(int argc, char* argv[]) { foo f; }
 // other global helper functions, DLL exports, and whatnot

もともとはJavaから来たものですが、インターフェイスやメソッドの名前が変更された場合に1か所だけを変更する必要があること、クラス内のさまざまなインデントが好きな場合など、いくつかの理由で常にこの2番目の方法に固執しています。それらの実装を見ると、foo::fooよりもfooの方が読みやすい名前であることがわかります。

どちらの方法でもプロとコンを集めたい。多分まだ他の方法がありますか?

私のやり方の1つの不利な点は、もちろん、時々のフォワード宣言の必要性です。

12
Felix Dombek

2番目のバージョンの方が記述は簡単ですが、インターフェースと実装が混在しています。

ヘッダーファイルを含むソースファイルは、ヘッダーファイルが変更されるたびに再コンパイルする必要があります。最初のバージョンでは、インターフェイスを変更する必要がある場合にのみヘッダーファイルを変更します。 2番目のバージョンでは、インターフェイスまたは実装を変更する必要がある場合は、ヘッダーファイルを変更します。

さらに、実装の詳細を公開しないを実行する必要があります。2番目のバージョンでは不必要な再コンパイルが表示されます。

16

私はそれを'93 -95の2番目の方法でやりました。 5〜10個の関数/ファイルを含む小さなアプリを再コンパイルするのに数分かかりました(同じ486 PC上で..いいえ、クラスについても知りませんでした。私は14〜15歳でしたインターネットはありませんでした)。

したがって、初心者に教えることと専門的に使用することは、特にC++で、大きく異なるテクニックです。

C++とF1車の比較は適切だと思います。 F1カーに初心者を入れないでください(エンジンを摂氏80〜95度に予熱しない限り、カーは始動しません)。

第一言語としてC++を教えないでください。オプション2が一般的にオプション1よりも悪い理由を理解し、静的コンパイル/リンクの意味を少し理解して、C++が最初の方法を好む理由を理解する十分な経験が必要です。

3
Macke

2番目の方法は、私が完全にインライン化されたクラスと呼ぶものです。クラス定義を記述していますが、それを使用するすべてのコードはコードをインライン化します。

はい、コンパイラーはインライン化するタイミングとしないタイミングを決定します...この場合、コンパイラーが決定を下すのを支援しているため、実際には生成されるコードが少なくなり、高速になる可能性があります。

この利点は、関数の実装を変更する場合、それを使用するすべてのソースを再構築する必要があるという事実を上回る可能性があります。クラスの軽量性により、実装を変更することはありません。新しいメソッドを追加する場合は、とにかくヘッダーを変更する必要があります。

ただし、クラスが複雑になると、ループを追加する場合でも、この方法でループを実行する利点は低下します。

特に次のような利点があります。

  • これが「共通機能」コードである場合、ヘッダーを含めるだけで、そのソースを含むライブラリにリンクする必要なく、複数のプロジェクトからそれを使用できます。

インライン化の欠点は、実装の詳細をヘッダーに組み込む必要がある場合、つまり、追加のヘッダーを含める必要がある場合に問題になります。

テンプレートは、実装の詳細を含める必要があるため、特別なケースです。別のファイルでは不明瞭になる可能性がありますが、そこにある必要があります。 (インスタンス化を使用するそのルールには例外がありますが、通常はテンプレートをインライン化します)。

2
CashCow

実行可能ファイルが大きくなる場合は重要ではないか、trueですが、ヘッダーファイル内のコードが多いほど、コンパイラーは速度を最適化する機会が増えます。

ヘッダーのみのライブラリを作成するかどうかを決定する の場合、このトピックはあなたの懸念の1つにすぎません。

1
davidvandebunte