C ++とJavaの抽象クラス/インターフェースには異なる使用原理がありますか


13

Herb Sutterによると、実装を可能な限り分離するために、C ++の抽象クラスよりも抽象インターフェイス(すべて純粋な仮想関数)を好むはずです。私は個人的にこのルールが非常に役立つと感じていますが、最近、多くのJavaプログラマーとチームに参加しましたが、Javaコードにはこのガイドラインは存在しないようです。関数とその実装は、非常に頻繁に抽象クラスに配置されます。だから、C ++でさえハーブサッターをすべて間違っているのか、それともJavaと比較してC ++の抽象関数の使用に一般的な違いがあるのか​​。実装コードを持つ抽象クラスは、C ++よりもJavaの方が賢明ですか?


1
私はいくつかの疑念を抱いていたが、最終的にここに置いたのは、Java ooについて欠落している設計原則のせいかもしれないからだ。したがって、一般的なアドバイスではなく、言語を使用する権利と誤りについての詳細です。
マーティン

インターフェイスは純粋に仮想的であるように意図されています。抽象クラスの考え方は、それらが部分的に実装されていることであり、コードを不必要に繰り返すことなくギャップを埋めることは実装次第です(たとえば、抽象クラス呼び出しwrite(int)からのwrite(byte))

1
おそらく関連する:stackoverflow.com/q/1231985/484230は、Javaの抽象クラスを好む理由を示しています。C ++の場合、この理由は、インターフェイスレベルで機能を追加できるフリー機能のexistanceのために成立していないようだ
マーティン・

1
私はゴールデンルールは「葉以外のクラスを抽象化する」ことだと思いますが、それは「純粋な」または「空の」要件のみを作成しません。
ケレックSB

1
それがあなたのために働くなら、それはあなたのために働きます。コードが最新の意見に従っていないと、なぜ人々がパニックに陥るのか本当にわかりません。
ジェームズ

回答:


5

OOPには構成と置換があります。

C ++には、多重継承、テンプレートの特殊化、埋め込み、および値/移動/ポインターのセマンティクスがあります。

Javaには、単一の継承とインターフェース、埋め込み、および参照セマンティクスがあります。

OOPスクールがこれらの言語を使用する一般的な方法は、オブジェクトの置換に継承を使用し、構成に埋め込みを使用することです。ただし、共通の祖先とランタイムキャストの方法も必要です(C ++ではが呼び出されdynamic_cast、Javaでは別のインターフェイスに問い合わせるだけです)。

Javaは、これをすべて独自のjava.lang.Objectルート階層で行います。C ++には事前定義された共通のルートがないため、同じ「画像」に到達するために少なくとも定義する必要があります(ただし、これはC ++の可能性を制限します...)。

その後、コンパイル時のポリモーフィズム(CRTPと考えてください)と値のセマンティクスを持つ可能性は、「OOPオブジェクト」の概念をC ++プログラムに移植する方法に対する他の代替手段も提供できます。

埋め込みと暗黙の変換を使用して置換とプライベート継承を管理し、構成を管理し、実際には従来の学校のパラダイムを逆にするという異端を想像することさえできます。(もちろん、この方法は他の方法よりも20年若いので、それを行う際に幅広いコミュニティのサポートを期待しないでください)

または、すべてのクラスへの仮想共通ベース、フォームインターフェイス(実装なし)から最終クラス(完全実装)へのインターフェイスを実装します-parallelogram」継承スキーム。

OOPをjavaからC ++に比較すると、唯一のOOP方法が両方の言語の機能を制限していると仮定します。

C ++をJavaコーディングのイディオムに厳密に準拠させることは、JavaをC ++に似た言語として振る舞わせることがJavaを変性させるため、C ++を変性させます。

「感性」の問題ではなく、2つの言語が持つ「集約メカニズム」が異なることと、2つの言語を組み合わせた方法が異なるため、ある言語で他の言語よりも収益性が高くなります。


1
この答えは非常に興味深いと思います。なぜなら、言語機能をオブジェクト指向および設計原理のツールとして簡潔に説明しているだけであり、教義ではなくヘルプとしてのみ使用しているからです。ただし、C ++でooを実行する場合、共通のルートは必要ありません。これは単に間違っているだけでなく、演算子とテンプレート(これもまた指摘したように、Javaのメインツリー設計の非常に強力な代替手段です)があるためです。それとは別に、あなたのポイントはすべての答えで最も価値がある
マーティン

1
@Martin:「技術的な意味」あなたしている権利ではなく、(インスタンス化されたオブジェクトの実際の型は、プログラム入力に依存しているため)あなたはpolymorophismをランタイム必要があれば、「ルート」(「」である記事、ないのショートカット」 「唯一無二」)は、すべてのオブジェクトを「いとこ」にし、階層を実行時歩行可能にします。異なるルートは、互いに関連していない異なる祖先を起源とします。これが「良い」か「悪い」かは、イディオムではなくコンテキストの問題です。
エミリオガラヴァリア

それは本当だ。私はあなたが人工的にc ++プログラム全体に1つの一般的なルートを提供することを言及していると思い、Javaと比較して、それが存在しないという欠陥と考えました。ただし、編集後は、ポイントを明確にします。再びありがとう
マーティン

12

原則は両方の言語に当てはまりますが、公正な比較を行っているわけではありません。C ++の純粋な抽象クラスとJavaインターフェイスを比較する必要があります。

C ++でさえ、いくつかの関数を実装した抽象クラスを持つことができますが、純粋な抽象クラス(実装なし)から派生します。Javaでは、インターフェイスから派生できる(実装なしの)同じ抽象クラス(いくつかの実装あり)があります。


したがって、C ++のインターフェイスクラスよりも抽象クラスを好むのはいつですか。私は常にC ++でインターフェイスと非メンバー関数を選択しました。
マーティン

1
デザインに依存する@Martin。基本的に、常にインターフェイスを優先します。しかし、「常に」のルールは...例外を持っている
Luchianグリゴール

確かに真実ですが、Javaコードでは、大部分を占める抽象クラスを見ています。これは、インターフェイスで動作する無料の関数がjavaでは不可能であるという事実によるものでしょうか?
マーティン

3
@Martinの無料の関数はJavaではまったく使用できないため、それが理由かもしれません。良いスポット!あなた自身の質問に答えました!自分で答えを追加できます、それでいいと思います。
ルシアングリゴール

4

一般に、JavaとC ++には同じOO原則が当てはまります。ただし、1つの大きな違いは、C ++が多重継承をサポートしているのに対し、Javaでは1つのクラスからしか継承できないことです。これが、多重継承の欠如を補い、おそらくそれでできることを制限するために、Javaが私が信じるインターフェースを持っている主な理由です(多重継承の濫用に対する多くの批判があるので)。したがって、おそらくJavaプログラマーの心の中には、抽象クラスとインターフェースの間に強い区別があります。抽象クラスは動作を共有および継承するために使用されますが、インターフェイスは単に追加機能を追加するために使用されます。Javaでは、1つのクラスからしか継承できないことを覚えておいてください。ただし、多くのインターフェイスを使用できます。ただし、C ++では、純粋な抽象クラス(つまり「C ++インターフェイス」) Javaインターフェイスの目的とは異なり、動作を共有および継承するために使用されます(ただし、関数を実装する必要があります)。したがって、使用方法はJavaインターフェイスとは異なります。


0

デフォルトの実装を使用することが理にかなっている場合があります。たとえば、すべてのサブクラスに適用できる一般的なPrintError(string msg)メソッド。

virtual PrintError(string msg) { cout << msg; }

本当に必要な場合はそれでもオーバーライドできますが、クライアントに汎用バージョンを呼び出すことを許可することで、クライアントの手間を節約できます。

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