Varsity で C を学んでから 2 か月足らずですが、来年は C++ に移行する予定です。
将来 C++ に移行するのに役立つ C プログラミングで取り入れるべき習慣はありますか、それとも完全に別々に考えるのが最善ですか?
C を学んでから C++ を学んだとき、C でのコーディング方法に何か変化はありましたか?
Varsity で C を学んでから 2 か月足らずですが、来年は C++ に移行する予定です。
将来 C++ に移行するのに役立つ C プログラミングで取り入れるべき習慣はありますか、それとも完全に別々に考えるのが最善ですか?
C を学んでから C++ を学んだとき、C でのコーディング方法に何か変化はありましたか?
すでに多くの良い答えがあります。私はもっと「考え方志向」になります。
「データの動作」は C で実行できますが (そして実行されます!)、C++ では、これを簡単に実装するために必要なすべてのものに既にアクセスできます: カプセル化、コンストラクタ、オーバーライドのオーバーロード、テンプレートなど.
この「データは振る舞うべき」という考え方は、C++ でコーディングする際の非常に優れた指針であることがわかりました。
C で実行できる多くの C++ 機能を見つけることができ、学習しない言い訳としてそれを使用する人もいます。この考え方は危険です (これは、一部の投稿で見られる「C++ を拡張ではなく、新しい言語として扱う」部分です)。
C++ を C++ の方法で書くことを避けることの副作用は、C++ 開発者が C++ コードを理解することを想定している一方で、C のみの機能で C++ シュガーを模倣する小さな個人的なフレームワークを理解することを想定していないことです。実際、彼/彼女はあなたのフレームワークには興味がありません。本当のことを言うと、彼/彼女はあなたに同情/軽蔑を感じるだけです。最終的に、C++ シュガーの代わりにあなたのフレームワークを使用しなければならない場合、彼/彼女はあなたを嫌うでしょう。
「私は C のやり方でこれを行うことができる」などの指導原則は、ワゴンを逃すだけです。この種の C 中心の考え方がすでにある場合は、C++ の学習をまったく開始しない方がよいでしょう。
あなたが選んだ言語は決して最高のものではありません。あなたは最高になるはずです。C++ コードを記述する場合は、C++ の方法で記述します。
構造体を C コンパイラでコンパイルできるように型定義するのは悪い冗談です。参照の代わりにポインターを使用することは、将来の自分への平手打ちです。これextern "C"
はコードを弱くするだけで、強くはしません。そしてvoid *
、一般性のために使用すると、見事に苦痛な方法であなたの頭を取り除くために喜んでお金を払う仲間の C++ コーダーの数が増えるだけです。
本当に必要でない限り、わざわざ C 互換のコードを書く必要はありません。
決して使用しない機能のために、時間のかかるコーディング スタイルで自分自身を圧迫するだけです。
低レベルで作業すると、一部の開発者に奇妙な影響があります。彼らは、コンパイルされたコードを自分たちでコントロールできると信じています。この制御をより高いレベルの構造に委任することは、彼らにとって困難です。
その良い例は、コンストラクター/デストラクタ パターンを捨てることです。なぜなら、「コンストラクターには時間がかかりすぎることがある...自分のやり方でやったほうがいい...」からです。
C++ コンパイラは、明らかに最適化されていないコードを最適化できます。実際、コンパイラによって生成されたコードは、自分が生成したと信じているものとはかなり異なる場合があります。
コンパイラよりも優れた/賢くなろうとしないでください。理由は次のとおりです。
したがって、コンパイラを信頼してください。
コードの生成を細かく管理しないでください。自分で作業を行い、コンパイラに任せてください。
この点は、低速/非効率的なコードの生成を正当化するために使用しないでください。時期尚早の最適化がすべての悪の根源である場合でも、言語とコンパイラに関する知識を使用して、優れた効率的なコードを生成する必要があります (次のポイントを参照)。
たとえば、仮想メソッドが関数呼び出しに 1 つの間接性を追加するという事実は、一部の人々にとってはパフォーマンスが劇的に低下することを意味します。実のところ、パフォーマンスの問題は別のところにあることがよくあります。
無知は言い訳になりません。
各 C++ コンストラクト (つまり、インライン化、参照、コンストラクター、デストラクター、例外、関数のオーバーロード、関数のオーバーライド、テンプレート、仮想関数など) に対して生成されるコードを理解します。何が最適化され、何が最適化されないかを把握します。
このようにして、必要のないものにお金を払わないだけでなく (これは C++ の指針となる原則です)、ゼロのコストで多くをもたらすものから利益を得ることもできます。
C++ で研究を行っている人で、生まれた日には私たちのほとんどよりも C++ が上手だった人がいます。Stroustrupを無視しても、 Meyers、Abrahams、Alexandrescu、Sutterなどの名前が定期的に新しいアイデアと一緒に現れます。その異質な外観にもかかわらず (またはその結果として)、STL は革命的なライブラリです。また、 Boostのようなライブラリは、一部の完全なフレームワーク (Java や .NET API など) と比較すると「サイズが小さい」にもかかわらず、学習用に提供される優れたコードの大規模なリポジトリです。
新しい機能が「奇妙」または「異質」だとわかったからといって、それを過小評価しないでください。それを理解しようとすると、おそらく別のツールを自由に使用できるようになり、常に言語の習得が向上し、常に脳が機能するようになります。これは開発ビジネスでは良いことです.
「C++ への変換」に失敗した私が知っているほとんどの人は、この機能またはこの機能を理解しようとしなかったために役に立たないと思っただけです。
それが何かわからない場合は、それを学びましょう。
RAII を使用しないと、C++ コードは、コンパイル エラーを回避する単なるバグ コードになります。
RAII は、C++ の最も重要な概念です。
他のすべては関連しています。
おそらく最善のアドバイスは、それらを完全に別の言語として扱うことです。はい、ほとんどの C コードは C++ コンパイラでコンパイルできますが、一般的には良い方法ではありません。
C は非常に低レベルのハッカー言語です。あなたが見たもの、それがあなたの手に入れたものだ。ポインターと構造体があるため、ポインターと構造体を使用します。型の安全性はほとんどないため、型の安全性を可能な限り無視します。
一方、C++ では、膨大な数の抽象化が可能です。通常、ポインターではなく、概念的にはポインターとして動作しますが、そうではない (またはそうでない可能性がある) イテレーターを使用することをお勧めします。
型情報を破棄する代わりに (たとえば、関数が void* を受け入れて、任意のポインター型で動作するようにする)、テンプレートを使用して型の安全性を保持し、同じ単一の関数定義を再利用することができます。
また、複雑なアルゴリズムを単純な事前定義されたビルディング ブロックで表現できる優れた標準ライブラリが提供されます。
C++ はマルチパラダイム言語です。ここでのいくつかの回答は、C++ はオブジェクト指向であると述べていますが、これは部分的に真実です。はい、オブジェクト指向コードをサポートしていますが、それは C++ではありません。
C++は、OOP よりも好まれることが多いジェネリック プログラミングもサポートしています。関数型プログラミングのサポートも一部限定されています。もちろん、C スタイルの手続き型プログラミングもサポートしています。C++ の秘訣は、これらすべてを理解することです。そうすれば、いつどれを使用すればよいかがわかります。これが C++ の強みであり、これらすべてのパラダイムを切り替えて組み合わせることができる能力です。C++ を OOP 言語と呼ぶ人は、それを改善された C と呼ぶ人たちと同じように、この点を見落としています。どちらのスタイルでもコードを記述できますが、どちらもそれ自体に価値はありません。C はより優れた C ライクな言語であり、より優れた OOP 言語はたくさんあります。1 つのパラダイムに固執したい場合は、そのために設計された言語を使用してください。
ここで、C と C++ は「完全に異なる」と主張する人が何人いて、「C++ はオブジェクト指向であり、C はそうではない」と主張するのはおかしいです...
まず、C++ は当初、C 言語の拡張として設計されました。実際、C++ 標準ドキュメントはC 標準を参照しています。多くのことが C++ では C とは異なる方法で行われていることは事実ですが、この 2 つが完全に分離していると主張するのは少し行き過ぎです。優れた C コードは C++ コンパイラでコンパイルできます。些細な問題については、C と C++ のソリューションはほぼ同じに見えます。
次に、C++ が「オブジェクト指向言語」であると思い込まないでください。C++ はオブジェクト指向をサポートする言語です。ただし、汎用プログラミングと手続き型プログラミングもサポートしています。C++ の OOP の側面だけに焦点を当てると、その能力の多くが失われます。
char *
身につける習慣については... C スタイルの文字列 ( ) や配列 ( )に執着しすぎないでくださいint foo[]
。string
はるかに強力な (そして便利な) 置換があるため、どちらも C++ ではめったに使用されませんvector
。
ポインタと動的メモリ割り当てに細心の注意を払ってください。優れた C++ コードにはそれらがほとんどありませんが、それらがどのように機能するかを認識しておく必要があります。そうするうちに、優れた C++ コードがそれらをカプセル化したり、参照に置き換えたりして、製品品質のコードにあまり現れない理由も理解できます。
C コードを設計するときは、struct
関連するデータ (アドレスのフィールドなど) を保持することから始めて、そのタイプの構造体 ( 、 など) で機能する関数を作成address_read( struct address_t * )
しaddress_write( struct address_t * )
ますaddress_modify_name( struct address_t *, char * )
。main()
これらの関数を適切な順序で呼び出す関数を最後に追加します。関数ではなく、データがプログラムの重要な部分です。これにより、C++ (およびオブジェクト指向) へのステップが容易になります。
他にもありますが、1 つの SO 投稿ですべてに答えているとは言いません。:-)
手に入れることができれば、C++ Bjarne Stroustrup の作成者による The C++ Programming Languageの最初の 3 つの章をお勧めします。
特に、「読者への注意事項」と「C++ のツアー」は、C++ が C とどこでどのように異なるかをよく理解し、さらなる学習に集中するのに役立ちます。もちろん、C++ を使用する場合は、本全体が近くにあると便利です。
あなたの状況にとって興味深いことに、第1章で、Bjarneは実際に言っています
「C++ の前に C を学ぶ必要があるかどうかについての継続的な議論において、私は C++ に直接行くことが最善であると固く確信しています」.
もちろん、彼はそうするでしょうが、彼の推論を受け入れるなら、できるだけ早く C++ に飛び込むのが最善でしょう。
言語を分けてください。
C と C++ は似ているように見えるかもしれませんが、似た構造に対して異なる規則を持つ異なる言語です。一方を他方から分離できれば、なおさらです。
C++ に切り替えるときは、次のことを忘れる (互換性のない別の方法を学ぶ) 準備をしてください。
C ++に移行しているということは、クラスまたはより優れたライブラリが必要だと感じたことを意味します。それが私が感じることです。また、Cのバックグラウンドを使用して、C++のより優れた機能を学習しています。これまで、主に[クラスとテンプレートを除いて]ベクトルを見てきました。
言語が似すぎているように感じます
それらを完全に別々に考えてください。
私の推測では、あなたが学習するC ++は、おそらく過度にオブジェクト指向になることはないでしょう。少なくとも、私の大学にはありませんでした。基本的にCプログラムとしてC++プログラムを実行しました。
ポインタの基本を理解するとともに、クラスの実装方法を確実に読んでください。
ファイルのI/O処理も異なります...iostream関数を実装する構文をfstreamで読み取る代わりに。
単純なC++プログラムのチュートリアルをWebで探してください... CodeProjectは常に優れたリソースです。
C++ プログラムはまったく異なります。C++ の要素を C++ 用に改善しようとするよりも、C++ の学習に時間を費やしたほうがよいでしょう。
たとえば、単純な「Hello World」プログラムでさえ、かなり異なります。
子:
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
return 0;
}
C++:
#include <iostream>
int main()
{
std::cout << "Hello, world!\n";
}
(ここからの例)。
「printf」は関数ですが、「cout」は関数ではなく、ostream クラスのインスタンスです。
さらに読む:iostream。
クラスのメソッドと抽象メソッドを模倣するために、できるだけ構造体と関数ポインターを使用してください。
たとえば、C を使用して車両と車両から派生した車を定義する場合は、次のように記述します (申し訳ありませんが、コードをチェックしません :-) ):
struct Vehicle
{
void (*checkFuel)(Vehicle*);
void (*start)(Vehicle*);
void (*move)(Vehicle*);
void (*stop)(Vehicle*);
}
void start1(Vehicle* v)
{
v->checkFuel(v);
printf("START!");
}
void start2(Vehicle* v)
{
v->checkFuel(v);
printf("VROOOOMM!");
}
struct Car
{
Vehicule base;
int (*klaxon)(Car*);
}
Vehicule* newVehicule()
{
Vehicule* v=(Vehicule*)malloc(sizeof(Vehicule));
v->start= start1;
v->move=
(...)
return v;
}
Car* newCar()
{
Car* c=(Car*)malloc(sizeof(Car));
Vehicule* v=(Vehicule*)c;
v->start= start2;
v->move=
(...)
c->kaxon=(...)
return c;
}
ここにいくつかのポイントがあります:
1) ポインターに習熟していることを確認してください。配列とポインターがどのように機能するか、それらの類似点と相違点に注目してください。
2) c を完成させる最善の方法は、プログラムを書くことです。できるだけ多く書いてください。手始めに、いくつかのライブラリ関数のカスタム関数を作成できます。Strcpy、strcmp、strncpy、memcpy、memmove を試してみてください。
3) デバッグの方法を学びます (Gdb は本当にクールです)。
4) 特定のコーディングスタイルに従い始め、それに固執するように努めます。
5) コードには常に意味のあるコメントを付けてください。
C と C++ のプログラミング スタイルはまったく異なります。C++ はオブジェクト指向プログラミングで、C は手続き指向プログラミングです。C++ プログラミングは、クラス/オブジェクトを使用して現実世界の問題をシミュレートするのに最適です。ただし、ポインター、構造体、演算子、キャスト演算子、データ処理などの基本的な概念は両方で同じです。構造体とクラスは似た概念ですが、厳密には異なります。したがって、構造体、ポインター、演算子、およびメモリ管理を使用したプログラミングに集中できます。あなたは「C」で学んでいます
C++ はオブジェクト指向ですが、C はそうではありません。ポインタコードをきれいに保ち、関数/メソッドにコメントを付けたり、#IFDEFを使用して無限のプリプロセッサループを取得しない方法を理解したりするなどの一般的なこと。
ただし、オブジェクト指向のアプローチは、実際にオブジェクトについて考えてコーディングするのにより適していることがよくあります。したがって、新機能の違いについて考える必要があります。
関数ポインタ。Googleの最初のヒット.