C++OpenSiv3D入門講座 Vol. 01 クラスの基本

C++OpenSiv3D入門講座

今回はC++でのHello World、クラスの基本的な使い方について学ぶ。 演習では、実際にSiv3Dを用いてPlayer,Enemyを生成し、動かす。

Hello World!

C++流のHello World! C++ではstd::coutが用意されており、それを使って出力ができる。 std:: とは、「stdという名前空間にある」という意味。

#include <iostream>

int main(){
    std::cout << "Hello World!!" << std::endl;
    return 0;
}

出力

Cのprintf関数では%dや%sなどを使って型を指定する必要があったが、std::coutでは型を指定しなくても自動的に型を判定・表示してくれる。

#include <iostream>

int main(){

    int a = 12;
    double b = 3.14;
    char str[100] = "abcde";

    std::cout << a << " " << b << " " << str << std::endl;

    return 0;
}

入力

std::cinを使うと入力されたデータを変数に入れられる。

#include <iostream>

int main(){

    int input;
    std::cout << "年齢を入力してください" << std::endl;
    std::cin >> input;//inputに入力された数値を代入

    std::cout << "あなたは"<< input << "歳なんですね。" << std::endl;    

    return 0;
}

クラスの基本的な書き方

クラスは以下のように定義でき、インスタンス(実体)化して使う。 クラスの要素には.(コンマ)を使ってアクセスできる。 クラスは変数を要素に持つことができ、メンバ変数という。

#include <iostream>

class MyClass{
public:
    int a;
    int b;
};

int main(){

    MyClass obj; // インスタンス化
    obj.a = 10;
    obj.b = 20;
    std::cout << obj.a << "," << obj.b << std::endl;

    return 0;
}

二次元上の座標や、2次元ベクトルを表すクラス、Vector2を作った。 クラスの要素には.(コンマ)を使ってアクセスできる。 クラスは関数を要素に持つことができ、メンバ関数という。(下の例ではsetData関数がメンバ関数

#include <iostream>

class Vector2{
public:
    int x;
    int y;
    void setData(int _x, int _y){
        x = _x;
        y = _y;
    }
};

int main(){

    Vector2 obj;
    obj.setData(13, 29);
    std::cout << obj.x << " " << obj.y << std::endl;

    return 0;
}

コンストラク

さっきの例ではVector2クラスを作った後、setData関数をいちいち呼ばなければならない。 初期化をいちいち行うのは手間がかかるので、C++ではクラス生成時に呼び出されるコンストラクタというものを定義できる。

コンストラクタの書き方

クラスの名前(引数){ 初期化処理... }

Vector2クラスのコンストラクタ例

#include <iostream>

class Vector2{
public:
    int x;
    int y;

    Vector2(int _x, int _y){
        x = _x;
        y = _y;
    }
};

int main(){

    Vector2 obj{ 1, 2 }; //インスタンス化、コンストラクタの引数を{}内に指定
    std::cout << obj.x << " " << obj.y << std::endl;

    return 0;
}

デストラク

オブジェクトが破棄されるときにデストラクタが呼ばれる。

デストラクタの書き方

~クラスの名前(引数){ 初期化処理... }

デストラクタの例

#include <iostream>

class MyClass{
public:
    ~MyClass(){
        std::cout << "デストラクタが呼ばれました" << std::endl;
    }
};

int main(){
    std::cout << "メイン関数に入りました" << std::endl;

    MyClass obj;

    std::cout << "メイン関数を抜けました" << std::endl;

    return 0;

}

メイン関数を抜ける時オブジェクトが破棄されるのでデストラクタが呼ばれる。

アクセス修飾子

publicやprivateをアクセス修飾子と言う。 publicの要素はクラス外からアクセスでき(公開)、 privateの要素はクラス外からアクセスできない(非公開)。 何も指定されていなければprivateメンバになる。 privateメンバ変数を用いることで、外から直接書き換えられたくないメンバ変数を書き換えることが出来ないようにできる。 privateは隠蔽、カプセル化などにおいて重要な機能だが、この講座では割愛する(基本的に全てpublicを使い、privateはあまり使用しない)。

#include <iostream>

class MyClass
{
    int a;
public:
    int b;
private:
    int c;
};

int main(){

    MyClass obj;

    //コメントを外すとコンパイルエラー

    //obj.a = 100;
    //obj.c = 100;

    obj.b = 100;

    return 0;
}

以下のようにすると、クラスの外から値を参照できるが、書き換えることは出来ないようにできる。

#include <iostream>

class MyClass
{
private:
    int data;
public:
    MyClass(){
        data = 3;
    }
    int getData(){
        return data;
    }
};

int main(){

    MyClass obj;

    // コメントを外すとコンパイルエラー
    // obj.data = 100;

    std::cout << obj.getData() << std::endl;

    return 0;
}

const変数

constをつけると値を変更不可能な変数を作ることができる。#defineの代わりに使って、定数を設定する時などに使える。

#include <iostream>

int main(){

    const int a = 100;

    //コメントを外すとコンパイルエラー
    //a = 200;

    std::cout << "aの値は:" << a << std::endl;

    return 0;
}

まとめ

  • std::coutで出力、std::cinで入力ができる。
  • クラスの定義とインスタンス化、メンバ変数・メンバ関数へのアクセスの方法を学んだ。
  • クラス生成時にはコンストラクタが呼び出され、オブジェクトが破棄されるときにデストラクタが呼び出される。
  • publicの要素はクラス外からアクセスでき、privateの要素はクラス外からアクセスできない。
  • constをつけると値を変更不可能な変数を作ることができる。

演習問題(コンソール)

  1. 以下のプログラムをstd::coutとstd::cinを使って書き直せ。
  2. #include <iostream>
    
    int main() {
        int input; //入力用
    
        printf("整数値を入力してください:");
        scanf("%d", &input);
    
        printf("入力された値は、%dです。\n", input);
    
        return 0;
    }
    
  3. 以下の様なクラスVector3を作った。
    • 適当なコンストラクタを作れ。
    • x,y,zの値を表示するメンバ関数showを作り、動作を確認せよ。
    • x*y*zの値を表示するメンバ関数showMultipleを作り、動作を確認せよ。
    class Vector3{
    public:
        int x, y, z;
    };
    

演習問題(OpenSiv3D)

  1. 以下の様なPlayerクラスを作り、矢印キーで動くようにせよ。
    class Player{
    public:
        double x, y, speed;
    
        Player(){
            x = 320.0;
            y = 240.0;
            speed = 50.0;
        }
        void update(){
            //ここを実装
            //矢印キーで移動
        }
        //自機(円)を描画
        void draw(){
            Circle{ x, y, 30.0 }.draw(Color{ 0, 0, 255 });
        }
    };
    
  2. Playerクラスの実体を作り、メインループ内でupdate関数とdraw関数を呼び出してPlayerクラスを動作させよ。
  3. 以下の様なEnemyクラスを作り、Playerクラスと同様に実体を作り動作を確認せよ。 今回作るEnemyはただ下に移動するだけでよい。
  4. class Enemy{
    public:
        double x, y, speed;
    
        //ここに座標と速さを指定できるようなコンストラクタを実装  
    
        void update(){
            //ここを実装
            //下方向に移動
        }
        //敵(円)を描画
        void draw(){
            Circle{ x, y, 30.0 }.draw(Color{ 255, 0, 0 });
        }
    };
    

ヒント

OpenSiv3Dでの処理は基本以下のような形になる

# include <Siv3D.hpp>

void Main()
{
    //毎フレーム使う変数の作成やゲーム開始前の処理

    while (System::Update())
    {
        // ここに書いた内容が毎フレーム実行される
    }
}
  1. while内でプレイヤーのインスタンスを作成すると、毎フレーム破棄されてしまう。

C++OpenSiv3D入門講座