CはC ++とどう違うのですか?


21

多くの人が、C ++はCとはまったく異なる言語であると言っていますが、Bjarne自身は、C ++はCから拡張された言語であるため、それが++由来していると述べています。それでは、なぜ誰もがCとC ++は完全に異なる言語であると言い続けるのでしょうか?C ++の拡張機能を除いて、CはC ++とどのように違いますか?


3
それらの使用方法が原因です。確かにC ++でCを書くことはできますが...すべきではありません。
エドS.

回答:


18

1980年代、C ++開発が始まったばかりの頃、C ++はCのほぼ適切なスーパーセットでした。それがすべての始まりです。
ただし、言語間の互換性は常に重要であると常に考えられてきましたが、時間が経つにつれて、CとC ++の両方が進化し、互いに分岐しています。

さらに、CとC ++の技術的な違いにより、これらの言語の典型的なイディオムが作られ、「グッドプラクティス」と見なされるものはさらに分岐しています。

これは、「C / C ++のような言語はない」や「CとC ++は2つの異なる言語」などと言っている人々の背後にある原動力です。CコンパイラとC ++コンパイラの両方で受け入れ可能なプログラムを作成することは可能ですが、このコードは一般に、優れたCコードの例でも、優れたC ++コードの例でもないと考えられています。


最初の段落が正しいとは思わない。Cは常に暗黙的なキャストを行ってvoid *いましたが、C ++はそうではありませんでした。(ダウン投票しませんでした)
代替案

5
@mathepic:「常に」を定義します。CはC ++からvoid *型を取りました。K&R Cでは、mallocがchar *を返していました
Nemanja Trifunovic

19

Stroustrup自身がよくある質問で答えています:

C ++は、Cのほぼすべてをサブセットとして保持するCの直接の子孫です。C ++は、Cよりも強力な型チェックを提供し、Cよりも広範なプログラミングスタイルを直接サポートします。効率)。同じ意味で、ANSI CはK&R Cよりも優れたCです。さらに、C ++はデータ抽象化、オブジェクト指向プログラミング、および汎用プログラミングをサポートします。

C.に「全く異なる」メイクC ++はあなたがいることを、オブジェクト指向プログラミングやジェネリックプログラミングのためのそれのサポートができ、ほとんど(あなたはより厳格な型チェックの世話をする限り)C ++コンパイラでコンパイルした後、純Cを書いて。しかし、あなたはまだCを書いています-あなたはC ++を書いていません。

C ++を作成している場合は、オブジェクト指向の機能とテンプレート機能を使用していることになります。これは、Cで見られるようなものではありません。


「これは、Cで見るようなものではありません。」このフレーズは面白いですね!「Cで見る」。C in C!これは一種の詩です。
ギャラクシー

13

簡単に言えば、Cでイディオムと見なされるものは、C ++でイディオムではありません。

CとC ++は、人々がそれらを使用する方法のために、実際には非常に異なる言語です。Cはミニマリズムを目指しており、C ++は多くの機能を備えた非常に複雑な言語です。

また、いくつかの実用的な違いもあります。Cはほとんどすべての言語から簡単に呼び出すことができ、プラットフォームのABIを定義することがよくありますが、C ++は他のライブラリから使用するのは非常に困難です。ほとんどの言語にはCでFFIまたはインターフェイスがあり、C ++で実装された言語(javaなど)もあります。


4
CスタイルのコードがC ++で非慣用的であるというだけではありません。Cスタイルのコーディングは、例外の安全性がないため、C ++では実際に問題があります。
dan04

4

C ++がオブジェクト指向プログラミングをサポートしているという明白な事実とは別に、ここにあなたの答えがあると思います:http : //en.wikipedia.org/wiki/Compatibility_of_C_and_C++

この記事には、Cでは問題ないがC ++では問題ないコード例を示しています。例えば:

int *j = malloc(sizeof(int) * 5); /* Implicit conversion from void* to int* */

多くの場合、CプログラムをC ++に移植することは簡単であり、大部分はコンパイルエラーの修正(キャストの追加、新しいキーワードなど)で構成されます。


4
そのようなプログラムを移植しても、C ++プログラムは提供されません。C ++コンパイラでコンパイルできるCを提供します。それはC ++にはなりません(結果のコードをC(クラスを持つCでさえも)呼び出します)。
マーティンヨーク

@MartinYork悪いCと呼び、セマンティクスが異なる可能性があることを指摘し、同意します。ただし、結果は明らかにCです。
デュプリケータ

2

C ++は、Cに新しい機能だけでなく、新しい概念と新しいイディオムを追加します。C++とCは密接に関連していますが、言語で効果的に記述するためには、その言語のスタイルで考える必要があります。最高のCコードでさえ、C ++のさまざまな長所とイディオムを利用することはできないため、実際にはむしろ悪い C ++コードではありません。


2

「拡張機能」では、可変マクロや何かのように追加したC ++のように聞こえますが、それだけです。C ++の「拡張機能」は言語の完全なオーバーホールであり、新しいC ++機能は元のC機能よりもはるかに優れているため、ほとんどの場合、元のC機能は完全に冗長であるため、Cのベストプラクティスに完全に取って代わります。C ++が単にCを拡張することを示唆することは、現代の戦車が戦争を遂行する目的でバターナイフを拡張することを示唆しています。


C ++にはない、Cにはない便利な機能の1つの例を列挙できますか?
ダークテンプラー

2
@DarkTemplar:RAIIを使用したイージーモードのリソース管理はどうですか?または、テンプレートを使用した素敵な汎用データ構造ですか?そもそも
DeadMG

1

違いは、Cでは手続き的に考えることと、C ++ではオブジェクト指向で考えることです。言語は非常に似ていますが、アプローチは非常に異なります。


Cには構造体もありませんか?Cファイル自体はモジュール(基本的にはオブジェクト)を分離していませんか?わからないどのような手続き型とオブジェクト指向の間の正確な違いがある...
ダークテンプラ

1
暗いあなたは私のポイントを示しています。それは、手続き的またはオブジェクト指向の方法で書くことを可能にする言語の制限ではなく、それは精神または考え方です。
アリ

0

C ++は、構文的にはCのスーパーセットになる可能性があります。つまり、Cプログラムの任意の構成体をC ++コンパイラでコンパイルできます。

ただし、Cプログラムで行うような方法でC ++プログラムを記述することはほとんどありません。リストは無限である場合もあれば、さらに調査を行って包括的なレポートとして掲載する必要がある場合もあります。ただし、重要な違いをもたらすいくつかのポインターを配置しています。

現在の投稿のポイントは、C ++には以下の機能があり、優れたC ++プログラマーは、Cに相当するものをコンパイルできる場合でも、プログラミングのベストプラクティスとして使用する必要があるということです。

C ++を介したC ++での実行方法

  1. クラスと継承。それは、プログラミング表現を非常に強力にする体系的なオブジェクト指向を可能にする最も重要な違いです。私は推測する-この点はより良い説明を必要としません。C ++を使用している場合-ほとんどの場合、クラスを使用する方が適切です。

  2. 民営化-クラス、さらには構造体にはプライベートメンバーがあります。これにより、クラスのカプセル化が可能になります。Cでの同等の方法は、アプリケーションが内部変数にアクセスできないように、オブジェクトをvoid *としてアプリケーションに型キャストすることです。ただし、C ++では、パブリッククラスとプライベートクラスを持つ要素を使用できます。

  3. 参照渡し。C ++では、参照に基づいて変更を行うことができます。そのためには、ポインターを渡す必要があります。参照渡しにより、コードが非常にきれいに保たれ、ポインターの危険に対してより安全になります。あなたも同様にCスタイルのポインタを渡し、それは動作します-しかし、C ++を使用している場合は、

  4. 新規および削除とmallocおよびfree。new()およびdelete()ステートメントは、メモリの割り当てと割り当て解除を行うだけでなく、チェーン内で呼び出されるdestructerの一部としてコードを実行することもできます。C ++を使用している場合-mallocとfreeを使用するのは実際には悪いことです。

  5. IOタイプと演算子のオーバーロード演算子のオーバーロードにより、コードが読みやすくなります。<<および>> io演算子についても同じです。これを行うCの方法は、関数ポインターを使用することです。

  6. 「string」を使用します。Cのchar *はどこでも動作します。したがって、CとC ++はほとんど同じです。ただし、C ++を使用している場合は、文字列クラスを使用する方が常にはるかに優れています(そしてより安全です)。

C ++ 1 ではまだ好きではない機能。テンプレート-多くのコードで重いテンプレートを使用していませんが、ライブラリにとって非常に強力であることがわかります。Cにはこれに相当するものはほとんどありません。しかし、通常の日-特に数学的に行方不明の場合。

  1. スマートポインター-はい、非常にスマートです!そして、最もスマートなもののように-彼らはうまく始めて、後で乱雑になります!あまり使いたくない

Cで気に入っていること、C ++で見逃していること

  1. 関数ポインターを使用した多相アルゴリズム。Cでは、複雑なアルゴリズムを実行しているときに、関数ポインターのセットを使用できる場合があります。これにより、真のポリモーフィズムが強力になります。あなたがCであるとき++あなたは、CAN関数ポインタを使用する-それは悪いです。メソッドのみを使用する必要があります-それ以外の場合は、乱雑になる準備をします。C ++クラスのポリモーフィズムの唯一の形式は、関数と演算子のオーバーロードですが、それは非常に制限されています。

  2. 単純なスレッド。スレッドを作成するときはpthreadでした-それは非常に簡単で管理しやすいです。クラスに対して「プライベート」であるはずのスレッドを作成する必要がある場合になります(そのため、プライベートメンバーにアクセスできるようになります)。フレームワークにはブーストタイプがありますが、基本的なC ++にはありません。

ディパン。


0

特定の言語機能は、追加機能であっても、実際に言語を使用する必要がある方法全体を変更する可能性があります。一例として、この場合を考えてみましょう。

lock_mutex(&mutex);

// call some functions
...

unlock_mutex(&mutex);

上記のコードにC ++で実装された関数の呼び出しが含まれている場合、これらの関数呼び出しのいずれかがスローされ、これらの例外パスでミューテックスのロックが解除されないため、トラブルの世界に陥る可能性があります。

デストラクタは、プログラマがその時点でリソースを解放/解放することを忘れないようにするための便利な領域ではなくなりました。RAIIは実用的な要件になります。なぜなら、自明でない例でスローできるコードのすべての行を予測することは人間的に実行不可能であるためです(これらの行は現在スローされないかもしれませんが、後で変更される可能性があることは言うまでもありません)。別の例を挙げます。

void f(const Foo* f1)
{
    Foo f2;
    memcpy(&f2, f1, sizeof f2);
    ...
}

このようなコードは、通常Cでは無害ですが、C ++で大混乱に陥っているようなものです。これはmemcpy、これらのオブジェクトのビットとバイトをブルドーズし、コピーコンストラクターなどをバイパスするためです。このような機能が好きmemsetreallocmemcpy、など、Cの開発者の間で毎日のツールは、ビットのではなく、均質な方法で物事を見に使用され、メモリにバイトしながら、Cのより複雑で豊かな型システム++との調和のとれたではありません。C ++は、ユーザー定義型のより抽象的なビューを推奨します。

したがって、これらの種類の物は、C ++を、それを正しく使用しようとする人が、Cの単なる「スーパーセット」と見なすことをもはや許可しません。 。

私は、C ++をあらゆる点で完全に優れていると見なしているキャンプにはいません。実際、私のお気に入りのサードパーティライブラリのほとんどは、何らかの理由でCライブラリです。正確な理由はわかりませんが、Cライブラリは本質的によりミニマリストになる傾向があります(おそらく、このようなリッチタイプシステムがないため、開発者は、いくつかの大きな抽象化セットを構築せずに必要な最小限の機能を提供することに集中します)ただし、目的に合わせてC ++ラッパーを単純化して使用方法を調整するために、C ++ラッパーを配置することがよくありますが、それを行う場合でも、そのミニマリストの性質は望ましいものです。私は、そのような質を追求するのに余分な時間をかける人々にとって、図書館の魅力的な特徴としてミニマリズムが大好きです。そしておそらくCはそれを奨励する傾向があります。

私はC ++を頻繁に使用しますが、実際には、最も広いバイナリ互換性(およびFFI)のためにC APIを使用する必要がありますが、ヘッダーにCを使用しているにもかかわらず、C ++で実装することがよくあります。しかし、メモリアロケーターのレベルや非常に低レベルのデータ構造など、本当に低レベルに移行する場合(埋め込みプログラミングを行う人の中にはさらに例があると確信しています)、作業している型とデータにはvtable、costructors、destructorsなどの特定の機能がないと想定できるため、それらをシャッフル、コピー、解放、再割り当てするビットとバイトとして扱うことができます。非常に特に低レベルの問題については、Cが提供するより単純な型システムで作業すると役立つ場合があります。

明確化

ここで興味深いコメントが1つあります。もう少し詳しく答えたいと思います(ここでのコメントは文字数制限が非常に厳しいことがわかります)。

memcpy(&f2, f1, sizeof f2); また、Fooが所有するポインターを持っている場合はCの「hellfire reigning havoc」であり、さらに悪いことに、それを処理するツールもありません。

それは公正なポイントですが、私が注目していることはすべて、主にC ++の型システムとRAIIに焦点を当てています。例えば、X rayishバイトコピーする理由の一つmemcpyまたはqsort機能の種類が少なくCにおける実用的危険をもたらす破壊することであるf1f2(彼らも非自明な破壊が必要な場合)上記で明示され、デストラクタは、画像に移動するとき、一方、暗黙的かつ自動化されます(多くの場合、開発者にとって大きな価値があります)。それは、vptrsなどのような隠された状態でさえ、そのような関数がすぐにブルドーズすることは言うまでもありません。場合はf1、ポインタを所有し、f2シャローは一時的なコンテキストでそれらをコピーするので、所有しているポインターをもう一度明示的に解放しようとしても問題ありません。C ++では、コンパイラーが自動的に実行したいことです。

そしてそれは、より大きなのになった場合、「一般的にCで、場合資源管理に必要な明示は、多くの場合、通常より困難その何かがCで、一方、見落とすことになりますので、fooはポインタを所有している」++、我々はUDTを作ることができなくなっ自明単純に構築/破壊されないメンバー変数を格納するだけで構築可能/破壊可能になります(一般的に非常に役立つ方法ですが、memcpyまたはのような関数を使用したい場合はそうではありませんrealloc)。

私の主なポイントは、この明示性の利点を主張しようとすることではありません(もしあれば、それに伴うヒューマンエラーの可能性の増加の短所によってほとんど常に圧迫されます)memcpyand memmoveand qsortand memsetandなどの関数reallocC ++ほどの機能や機能が豊富なUDTを使用する言語には、他の場所はありません。それらは関係なく存在しますが、C ++開発者の大多数は、ペストのような機能を避けるのが賢明だと言っても過言ではないと思いますが、これらはCの非常に日常的な機能であり、私はdは、その型システムのほうがはるかに基本的で、おそらく「だらしない」という単純な理由で、Cでの問題が少ないと主張しています。X線のCのタイプとそれらをビットおよびバイトとして扱うことはエラーを起こしやすいです。そのような関数は言語の非常に基本的な機能と型システムの奨励するものと戦っているので、C ++でそれを行うことは間違いなくまったく間違いです。

しかし、それが実際にCの最大の魅力であり、具体的には言語の相互運用性とどのように関係しているかです。C#のFFIのようなものに、コンストラクタ、デストラクタ、例外、仮想関数、関数/メソッドのオーバーロード、演算子のオーバーロードなど、C ++の本格的な型システムと言語機能を理解させることは、はるかに困難です。 Cを使用すると、多くの異なる言語が直接FFIを介して、またはC APIを使用して目的の形式でエクスポートする方法(Java Native Interfaceなど)で直接インポートできるように、APIに関してはかなり標準的な言語になりました。 )。そして、その言語の相互運用性は私たちの場合の実用的な要件であるため、ほとんどの場合、Cを使用する以外に選択肢がありません(ただし、私はしばしば

しかし、ご存知のように、私は実用主義者です(または、少なくとも私はそうするよう努めています)。Cがこの最もファウルで、ひどく、エラーを起こしやすく、厄介な言語だった場合、私のC ++愛好家の一部がそれを主張しました(そして、どういうわけか、Cの憎しみにつながっていないことを除いて、私は自分をC ++愛好家と数えます)反対に、両方の言語をそれぞれの点と違いでより良く評価するという逆の効果がありました)、そして、私は現実の世界で最もバグが多くて漏れやすいものの形で現れると期待しています信頼性の低い製品とライブラリがCで記述されています。そして、私はそれを見つけません。私はLinuxが好きで、Apache、Lua、zlibが好きです。OpenGLは、そのような変化するハードウェア要件、Gimp、libpng、Cairoなどに対するその長いレガシーに耐えられると思います。少なくとも、言語がもたらすハードルは、有能な手でいくつかのクールなライブラリや製品を書く限り、行き詰まりをもたらすようには見えません。それが本当に私が興味を持っていることです。実用的なアピールを行い、「おい、クールなものがあります。それがどのように作られたのかを学びましょう。そして、言語の慣用的な性質にそれほど限定されないクールなレッスンがあります。使用している言語に合わせて」:-D


2
memcpy(&f2, f1, sizeof f2);また、CでFoo所有するポインターがある場合は"hellfire reigning havoc"であり、さらに悪いことに、それを処理するツールもありません。そのため、Cを書いている人はそれほどそんなことはしません
Caleth

@Caleth所有しているポインターでさえ明示的に所有しているポインターを解放することを単純化するもののいくつかは、そのため、たとえば1つの場所のみが元のメモリをまだ解放している場合、事実上浅いコピーに変わります(場合によっては、デザイン)。一方、デストラクタの関与により、両方のFooインスタンスが動的配列、ベクトル、またはこの効果の何かを破壊したい場合があります。いくつかの特殊なケースでは、特定のデータ構造を記述して、破壊が暗黙的ではなく明示的であるという事実に頼ることが役立つことがよくあります。
ドラゴンエナジー

@Caleth Foo所有ポインターがある場合、適切なコピー/移動ctor、dtor、値セマンティクスの使用などを与えることができ、はるかに豊かで安全なコードを持つことができるので、それは確かに怠なことです。しかし、データ構造やアロケーターを同種のレベルのビットとバイトで一般化したい場合、Cに手を伸ばすことが時々あります。私はC言語で作るもう少し自信ような仮定することによりビット
ドラゴンエナジー

@Calethしかし、私の場合、時折、メモリ内のビットやバイト以上のものを配置してアクセスするために物事を見るのに役に立たないアーキテクチャのいくつかの礎石があります(そして、通常、これらのケースはPOD以外を含みません)。これらは、私がまだCを好む少数の特殊なケースです。メモリアロケーターを想像すると、ビットとバイト、ボイドポインター、この種のこと、そして整列とプーリングに焦点を合わせたもの以外に、実際に動作するものはありません。そして、ビットとバイトを配ります。非常に特殊なケースでは、CはC ++よりも障害が少ないことに気付きます。
ドラゴンエナジー

私は時々 、Cのために達する他のケースのようなコードが実際に、より一般化し、抽象度の低いものとプリミティブに着目して再利用可能になるかもしれないケースであるAPI void filter_image(byte* pixels, int w, int h);簡単な例として、のように対立するものとしてAPI void filter_image(ImageInterface& img);、そのようなイメージインタフェースに結合我々のコードをだろう(適用範囲を狭める)。そのような場合、C ++で得られるものはほとんどないため、Cでそのような関数を実装することがあり、そのようなコードが将来の変更を必要とする可能性が低くなります。
ドラゴンエネルギー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.