Flat Leon Works

アプリやゲームを作ってます。

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#の両方にある機能

すべて挙げるとキリがないので、大雑把に紹介

  • 基本
    • コメント(文法も同じ)
    • ブロック文(文法も同じ)
    • 条件分岐(if,else if,else,switch,goto) *2
    • 反復(while,do while,for,範囲for*3 )
    • プリミティブ型(型名もだいたい同じ)
  • 関数
  • クラス
    • コンストラクタ、デストラクタ(ただし、C#のデストラクタはGCの都合上呼び出しタイミングが不定)
    • 移譲コンストラクタ
    • オーバーライド(virtualが必要な点も同じ)
    • メンバアクセス制御(public,protected,private) *5
    • 継承(文法もだいたい同じ。C#にはアクセス制御がないだけ)
    • 継承禁止(C++:finalC#:sealed)
    • 抽象メソッド(C++では純粋仮想関数)
  • 列挙型(C#enumC++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 ){}みたいなやつ)はできない
  • switch文でのフォールスルーは禁止。ただし、ラベルが連続している場合は可能
  • intなどの整数型のデータサイズが決まっている
  • 単純で無意味な式はコンパイルエラー(0;というような無意味な式はC++ではコンパイルが通るがC#ではコンパイルエラーになる)
  • オーバーライド時はoverrideを付ける必要がある(C++では任意)
  • 基底クラスでの仮想関数呼び出しがちゃんと動作する(オーバーライドされている場合はそちらが呼ばれる)
  • 引数の参照渡し(値の参照渡し)にはrefキーワードを使うが、C++と違い実引数側(呼び出し側)にもrefキーワードが必要
    • C++と違い、参照の参照渡しも可能

*1:執筆時点のUnityのデフォルト設定

*2:ただし、一部禁止項目あり

*3:C#ではforeach

*4:C#のデリゲートは複数の関数オブジェクトを格納可能という違いがある

*5:C#はこれに加えて internal がある

*6:C++メンバ関数の実装を場所を分けることならできるが、クラスの定義(宣言)を分割して行うことはできない

*7:C++にも属性構文はあるがユーザーで定義できない