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


12

C ++には、ヘッダーファイルの内容とcppファイルの内容に関するいくつかの異なるパラダイムがあることがわかりました。私の知る限り、ほとんどの人、特に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から来た私は、いくつかの理由で常にこの2番目の方法にこだわっています。たとえば、インターフェイスまたはメソッドの名前が変更された場合、1か所で何かを変更するだけです。それらの実装を見て、名前がにfoo比べて読みやすいことがわかりましたfoo::foo

どちらの方法でも賛否両論を集めたい。まだ他の方法がありますか?

私のやり方の欠点の1つは、もちろん、時折の前方宣言が必要なことです。


2
foo.cppfooクラスとは何の関係もないので、空のままにしておく必要があります(ただし、#includeビルドシステムを幸せにするためです)。
ベンジャミンバニエ

2
あなたの講師は非常識です。
モニカとの明るさのレース

回答:


16

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

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

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


1
+1私のプロファイラーはヘッダーファイルに配置されたコードをインストルメントしません-それもまた重要な理由です。
ユージン

この質問に対する私の答えをご覧になる場合、programmers.stackexchange.com / questions / 4573 / …クラスのセマンティクスに依存する方法がわかります。つまり、何を使用するか(特に、それが公開されている場合)ユーザーインターフェースと、システム内で直接使用する他のクラスの数)。
CashCow

3

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

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

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

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


この答えは、静的コンパイル/リンクについて少し詳しく説明した方が良いでしょう(当時は知りませんでした!)
Felix Dombek 14年

2

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

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

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

ただし、クラスがさらに複雑になり、ループを追加しても、この方法で行う利点は低下します。

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

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

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

実装の詳細を含める必要があるため、テンプレートは特別なケースです。別のファイルでわかりにくくするかもしれませんが、そこにある必要があります。(インスタンス化に関するルールには例外がありますが、一般的にはテンプレートをインライン化します)。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.