[C++] ドット演算子とアロー演算子

# はじめに
int型などに通常の変数とポインタ変数があるように、
クラスにも通常の変数とポインタ変数とが存在する。

この時の違いについて、メモした。

# 要点
C++では、オブジェクトを変数かポインタで定義するかで、メンバ関数の呼び出し方法が異なる。
* 変数の場合：ドット演算子（.） を利用
* ポインタの場合：アロー演算子（->） を利用

# 例
## 手順1. ヘッダーファイルの作成
クラスを定義するために、ヘッダーファイルを作成。

```c++
#pragma once

#include <bits/stdc++.h>

using namespace std;

// ヘッダファイル：クラスの宣言を記述。
// 注意：宣言より下のクラスの実装は、別ファイルに分けた方が良い。

class Television
{
    // データメンバ
    int power;
    int channel;
    int volume;

public:
    // コンストラクタ。オブジェクト生成時に自動で呼ばれる。
    Television(void);
    // デストラクタ。オブジェクト消滅時に自動で呼ばれる。
    ~Television(void);

    // メンバ関数
    // - 状態取得用
    int getPower();
    int getChannel();
    int getVolume();

    // - 状態設定用
    void setPower(int p);
    void setChannel(int c);
    void setVolume(int v);

    // - 状態表示用
    void printStatus();
};

// コンストラクタ。オブジェクト生成時に自動で呼ばれる。
Television::Television()
{
    power = 0;   // 電源オフ
    channel = 1; // チャンネル1。首都圏ではNHK。
    volume = 0;  // ボリューム0。
}

// デストラクタ。オブジェクト消滅時に自動で呼ばれる。
Television::~Television()
{
}

// メンバ関数
// - 値の取得用関数（getter）3つ
int Television::getPower()
{
    return power;
}

int Television::getChannel()
{
    return channel;
}

int Television::getVolume()
{
    return volume;
}

// - 値の設定用関数（setter）3つ
void Television::setPower(int p)
{
    power = p;
}

void Television::setChannel(int c)
{
    channel = c;
}

void Television::setVolume(int v)
{
    volume = v;
}

// - 状態表示用関数
void Television::printStatus()
{
    if (power == 1)
        cout << "電源はONです。\n";
    else
    {
        cout << "電源はOFFです。\n";
        return; // オフの場合は、ここから先へ進まずに終了。
    }

    cout << "チャンネルは" << channel << "です。\n";
    cout << "ボリュームは" << volume << "です。\n";
}
```

## 2. メンバ関数の呼び出し
### オブジェクトを変数で定義する場合（ドット演算子の利用）

```c++
#include <bits/stdc++.h>

#include "Television.h"

using namespace std;

int main()
{
    //----------------------------------------------------------------
    // 通常の変数でオブジェクトを定義した場合、
    // メンバ関数の呼び出しにドット演算子（.）を利用
    //----------------------------------------------------------------

    Television tv; // Television クラスの変数 tv を宣言
                   // クラスを「新しい型」として用いている
                   // この時点でコンストラクタが呼ばれる

    tv.printStatus(); // 確認のために状態表示

    cout << endl;

    tv.setPower(1);   // 電源オン
    tv.setChannel(8); // 8チャンネルにセット
    tv.setVolume(10); // ボリュームを10に
    tv.printStatus();

    cout << endl;

    tv.setChannel(4); // 4チャンネルにセット
    tv.printStatus();

}
```

### オブジェクトをポインタで定義する場合（アロー演算子の利用）

```c++
#include <bits/stdc++.h>

#include "Television.h"

using namespace std;

int main()
{
    //----------------------------------------------------------------
    // ポインタでオブジェクトを定義した場合、
    // メンバ関数の呼び出しにアロー演算子（->）を利用
    //----------------------------------------------------------------

    // テレビクラスのポインタの宣言
    // （ポインタtvp自体は、スタック領域に保存）
    Television *tvp;

    // テレビクラスのオブジェクトをヒープ領域に確保(new演算子の利用)
    // これにより、ポインタの指す先が決まる。 （ポインタtvpはヒープ領域に作られたオブジェクトを指すようになる。）
    tvp = new Television();

    tvp->printStatus();

    cout << endl;

    tvp->setPower(1);
    tvp->setChannel(8);
    tvp->setVolume(10);
    tvp->printStatus();

    cout << endl;

    tvp->setChannel(4);
    tvp->printStatus();

    delete tvp; // newで確保したオブジェクトをdeleteで解放
}
```

配列メモリを動的に確保する時と類似している点

- クラスをポインタで宣言
- new演算子でオブジェクトを生成。→ オブジェクトをヒープ領域に確保。これにより、ポインタの指す先が決まる。
- newで確保したオブジェクトのメモリ領域をdeleteで解放

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397136/d58a6fa2-ed07-9baa-b243-d483340122bf.png)

# 整理

最後に int などの型とクラスとで、通常の変数とポインタ変数の利用法の違いを整理。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397136/086ec583-8cdc-0b39-112b-3a793ceb04a1.png)

# 補足
Java や C# ではメンバ関数の呼び出しは全てドット演算子で統一されている。
なお、Java や C# でのクラス変数は全て内部的にはポインタのような振舞いをするので、new でメモリ確保する点など、利用法はむしろ C++ でのポインタに似ている。

# 参考

- [https://brain.cc.kogakuin.ac.jp/~kanamaru/lecture/prog1/13-03.html](https://brain.cc.kogakuin.ac.jp/~kanamaru/lecture/prog1/13-03.html)