7839

雑草魂エンジニアブログ

【C/C++】C++言語文法

C言語を学びなおして、引き続きC++言語の文法の基礎を学習した。備忘録として残しておく。

今回も、C言語に続き、一週間で身につくC++言語の基本を教材として使わせていただいた。これが無料公開されているなんて、本当に感謝しかない。

ファイル分割

C言語同様に、C++のライブラリを #include <ライブラリ名> で読み込むことができる。

C言語との違い

  • ヘッダファイルを読み込んでいるが、C++のライブラリ名に.hは不要である。
  • C言語の場合、変数や関数を読み込んでいた。C++の場合、様々な「クラス」(インスタンス)を読み込む。

名前空間

名前空間は、C++言語の重要な概念である。
名前の衝突(同じ名前を付けることで呼び出し先が曖昧になること)を避けることができる。

(名前空間名)::(変数名・クラス名など)
// 「::」はスコープ解決演算子
// ex. std::cout
// stdという名前空間のcout

毎回、「std::」と定義するのは面倒なので、任意のスコープの冒頭で「using宣言」をすることで省略が可能となる。

using namespace (名前空間名);
// ex. using namespace std;
// 「std::」を全て省略して、coutに参照できる

using namespace <-name-> で省略して、複数の名前空間で同じ名前の変数・関数名があった場合に、競合してしまうことがある。これでは、名前空間での識別が無意味になってしまう。そのため、省略したい名前空間の変数や関数のみを明示することもできる。

using (名前空間名)::(変数名・クラス名など)
// ex. using std::cout;
// coutのみ、「std::」を省略して参照できる

C言語では、同じ名前の関数を定義するとエラーになる。
C++言語には、オーバーロード(多重定義)という機能があり、関数名が同じでも、引数が異なっていれば定義可能。

cin/cout、ストリーム

C言語の入出力(scanf / printf 等)も使うことができるが、C++言語では独自の実装方法がある。Linuxの標準入出力と似ている。ストリームというインターフェースを介して、ファイルやコンソールから入力を受け付けたり、出力先として設定することができる。

f:id:serip39:20220123150108j:plain

#include <iostream>

int main(){
    int a;
    std::cin >> a;
    std::cout << "a=" << a << std::endl;
    return 0;
}
オブジェクト 説明
cin 標準入力(stdin)
cout 標準出力(stdout)
cerr 標準エラー出力(stderr, unbuffered(*1))
clog 標準エラー出力(stderr)

データの流れは、「>>」「<<」で決定する。

(*1)バッファリングとは、データを一時的に保存しておくこと。バッファからデータが掃き出すことをバッファのフラッシュという。バッファのフラッシュにより、画面に文字が表示される。cerrは、unbufferedとなっているので、毎回フラッシュが行われる。

入出力の書式や制御は、マニピュレータ(manipulator)で行うことができる。

マニピュレータ 説明
std::endl 改行文字を出力してバッファをフラッシュ
std::flush バッファをフラッシュ

詳細は、以下を参照してほしい。

クラス

  • C++言語のクラスは、C言語の構造体と似ている
  • 構造体は、複数の変数を1つにまとめたもの
  • クラスは、メンバとして変数と関数の両方を含めることができる
class CSample
{
public:
  CSample(); //コンストラクタ
  virtual ~CSample(); //デストラクタ
  void function(); //メンバ関数(メソッド)
  static void showAll();  //静的メンバ関数
private:
  int m_num;  //メンバ変数
  static int m_sum;  //静的メンバ変数
};
アクセス指定子 意味
public すべての範囲から呼び出し・読み出し可能
private 同一クラスまたは同一インスタンス内でのみアクセス可能
protected 同一クラスまたは同一インスタンスおよび、サブクラスおよびそのインスタンス内でのみアクセス可能

インスタンスを生成することなく利用するできる変数、関数を静的メンバ変数静的メンバ関数という。ただし、静的メンバ関数内では、静的メンバ変数のみしか使えないので注意が必要。

メンバへのアクセスを、そのクラスのメンバ関数(アクセスメソッド(*2))からしかできないように制限することをカプセル化(隠蔽)と言う。

(*2) setter, getter

// オブジェクト(インスタンス)の生成
CSample obj;

メモリの生成と消去

メモリの生成 メモリの消去
C言語 malloc()/calloc()/realloc() free()
C++言語 new演算子 delete演算子

malloc関数やfree関数では、コンストラクタ、デストラクタが呼び出せないため、C++では通常メモリの生成と消去には、new/deleteが用いられる。

コンストラクタ:インスタンス化時に、自動的に一度だけ呼び出される

クラス名::クラス名() : メンバ変数1(初期値1),メンバ変数2(初期値2)…
ex. CSample::CSample() : m_num(0)
{
  // インスタンス生成時に実行したい処理
}

デストラクタ:インスタンスが解放される直前に、自動的に一度だけ呼び出される

クラス名::~クラス名()
ex. CSample::~CSample()
{
  // 解放直前に実行したい処理
}

配列のメモリを解放する場合は、delete[]を用いる必要があるので注意。

#include <iostream>
int main()
{
    int *p = 0;
    int i;
    p = new int[10];  // int型10個分の領域を動的確保
    for(i=0; i<10; ++i)
    {
        p[i] = i;
        std::cout << p[i] << std::endl;
    }
    delete[] p;       // 動的に確保した領域を解放
    return 0;
}

継承(インヘリタンス)

  • 継承とは、基本となるクラスの性質を受け継ぎ、独自の拡張をすることである。
  • 継承元になるクラスを、親クラス、スーパークラスという。
  • 親クラスを継承して、独自の機能を実装したクラスを、子クラス、サブクラスという。
class Sub : public SupA, public SupB
{
  // Sub member
}
  • 子クラスのみにアクセスを許すメンバには、protected修飾子をつける。
  • 親クラス、子クラスに同じ名前、同じ戻り値の型、同じ引数をとるメンバ関数が存在する場合、子クラスのメソッドは、親クラスのメソッドをオーバーライドする。原則的に子クラスに定義されたものが実行される。

ポリモーフィズム多態性・多様性)

ポリモーフィズム 説明
オーバーロード コンストラクタを含め、すべてのメンバ関数が、引数、および戻り値が違っていれば、同じ名前のついた複数の関数(メソッド)を定義することができる。
オーバーライド 親クラスと同じメソッドが子クラスに存在する場合、子クラスのメソッドで上書きすることができる。
  • ポリモーフィズムを利用する利点は、メソッドの名前が統一されることにより、名前を覚える必要がなくなることや、記述ミスを減らせることなどが挙げれる。
  • オブジェクト指向では、原則的に同じ機能には同じメソッド名をつけることが好ましい。そうすることで、処理に統一感を持たせることができる。

まとめ

C言語に続き、C++言語の文法を学んでみた。C言語の上位互換であるC++言語は、より実装がしやすくなっていると感じた。JavaScriptなどのオブジェクト指向型言語であるC++言語は馴染みやすいと思えた。これからC++言語をもっと極めていきたいと思えた。