C#とC++の比較
C#を勉強中なのですが、C#はC++とかなり似ていながらも微妙な違いもあったりして、そこが結構ややこしいです。そこでC#とC++の違いをまとめてみました。
注意
- C#はC#3.0(.Net Framework 3.5) を想定*1しています
- C++はC++14あたりを想定しています
- 「C#とC++の比較」というよりは、「C++との違いで理解するC#」という感じの記事です
C++とC#の両方にある機能
すべて挙げるとキリがないので、大雑把に紹介
- 基本
- 型
- 関数
- クラス
- 列挙型(C#の
enum
はC++のenum class
に相当) - 演算子オーバーロード
- 例外機構
- 短絡評価
- 名前空間(ただし、C#では
::
ではなく.
を使う) - 名前空間の省略( C++:
using namespace XXX;
, C#:using XXX;
) - グローバル名前空間への明示的アクセス( C++:
::識別子
, C#:global::識別子
でアクセスする )
C++とC#の両方にない機能
- 名前付き引数(ただし、C#は4.0から可能)
C#にしかない機能
- ガベージコレクション(C++には標準ライブラリとして参照カウント式GCが存在)
- クラスの宣言が不要(ヘッダファイルを用意する必要がない)
- クラスの分割定義*6
- インターフェイス型
- メンバ変数の自動初期化(未初期化のローカル変数はコンパイルエラー)
- プロパティ構文
- ユーザー定義属性*7
- クラスに対するアクセス制御(
private class
など) - 逐語的識別子 : @を付けることで予約語も識別子として利用可能になる
- null 合体演算子(
??
) - オーバーフロー例外(デフォルトでは無効)
- 列挙型の文字列化
- 静的コンストラクタ
- 静的クラス(インスタンス不可+静的メンバのみ定義可能)
- 拡張メソッド
- 抽象クラス
- インターフェイス
- LINQ
- Nullable型
- 式木
C++にしかない機能
- プリプロセスマクロ(
#if
などはC#にもある) - コンストラクタでのメンバ変数の初期化
- 多重継承
- private継承、protected継承
- 非メンバ関数(C#ではメンバ関数しか許されていない)
- グローバル変数、static変数(staticメンバ変数はある)
- ポインタ
- const修飾(定数定義のための
const
と読み取り専用変数のためのreadonly
はある) - デフォルト引数(C#3.0時点では無し、C#4.0から導入)
- 無名名前空間(グローバル名前空間はある)
微妙に違うところ
- クラス定義の末尾にセミコロン不要
- クラスメンバのアクセス制御にコロンはつけない(C++では
public:
、C#ではpublic
) - 引数なしの関数の引数として
void
を記述することはできない(int func(void)
はC++では問題ないが、C#ではコンパイルエラー) this->
ではなく、this.
でメンバへアクセスする- C++では構造体とクラスの違いはデフォルトアクセス制御の違いのみだが、C#ではコピー時の挙動、継承の可否などの違いがある
- 移譲コンストラクタ(C#では
コンストラクター初期化子
)の書き方が異なる。C++:X():X(123){}
、C#:X():this(123){}
- 基底クラスの初期化方法が少しだけ異なる。C++:
Dog():Animal(123){}
、C#:Dog():base(123){}
- C++:
初期化子リスト
、C#:オブジェクト初期化子
。機能も微妙に違う。C#のオブジェクト初期化子
はC99の指示付きの初期化子に近い - C#のデストラクタは、GCの都合上C++と呼び出しタイミングが異なる。RAII目的ならばデストラクタではなく、using ステートメントを使う
- 値型と参照型の違い。C#では型によって値型か参照型かどうかが分かれる。C++では型に
&
を付けることで参照型になる - if文での暗黙のbool型変換が行われない。なので、
if(0)
と記述できない- なので、if文での変数定義(
if ( int a = 0 ){}
みたいなやつ)はできない
- なので、if文での変数定義(
- switch文でのフォールスルーは禁止。ただし、ラベルが連続している場合は可能
int
などの整数型のデータサイズが決まっている- 単純で無意味な式はコンパイルエラー(
0;
というような無意味な式はC++ではコンパイルが通るがC#ではコンパイルエラーになる) - オーバーライド時は
override
を付ける必要がある(C++では任意) - 基底クラスでの仮想関数呼び出しがちゃんと動作する(オーバーライドされている場合はそちらが呼ばれる)
- 引数の参照渡し(値の参照渡し)には
ref
キーワードを使うが、C++と違い実引数側(呼び出し側)にもref
キーワードが必要- C++と違い、参照の参照渡しも可能