C++セミナー(初級)構造体とクラス

HOME->講習会->プログラミングセミナー->C++セミナー(初級)


intやlongなどもともとC++に備わっている変数だけでも十分にプログラミングは可能ですが,ひとまとめにして一括で宣言したり,処理を行いたい場合もあります.ここでは,構造体とクラスについて紹介します.この内容はC++セミナー(中級)で学ぶオブジェクト指向につながるので理解しておきましょう.

目次

構造体
クラス
構造体とクラスの違い
コンストラクタとデストラクタ
構造体とクラスのポインタ
演習

構造体

複数の変数の集合体のことを構造体といいます.構造体を扱うには,まず構造体の定義を行います.

struct 構造体名{
    変数型 変数名;
    変数型 変数名;
    変数型 変数名;
};

変数型については,いくつも設定することができます.例えば,Humanと呼ばれる名前,体重,身長,年齢の情報を持つ構造体を定義するとなると以下のようになります.

struct Human{
    char name[20];
    double weight;
    double height;
    int age;
};

このように構造体が持つ変数のことをメンバー変数といいます.定義した構造体型は今までの変数宣言と同様に行うことができ,メンバー変数の参照は,「変数名.メンバー変数」というように行います.

構造体型 変数名;
変数名.メンバー変数名 = データ;
変数 = 変数名.メンバ変数;

では,先ほどのHuman型を実際に扱うプログラム例を以下に示します.

#include <iostream>
struct Human{
    char name[20];
    double weight;
    double height;
    int age;
};
int main()
{
    Human h1;
    std::cin >> h1.name >> h1.weight >> h1.height >> h1.age;
    std::cout << "Name: "<< h1.name << std::endl;
    std::cout << "Weight: " << h1.weight << std::endl;
    std::cout << "Height: "<< h1.height << std::endl;
    std::cout << "Age: " << h1.age << std::endl;
}

今回の例では,データが1つしかないためデータがあまり構造体のメリットが得られてはいませんが,多くのデータを操作する際には構造体が便利です.例えば,100人のデータを読み込んで,身長順で並び替えるといったときなどは,構造体を扱うと便利です.

クラス

構造体は,C言語にもありましたが,クラスはC++から追加された機能です.クラスでは,変数以外にも関数を持つことができます.クラス内で定義された変数や関数のことをメンバー変数メンバー関数といいます.

class クラス名{
private:
    変数型 変数名1;
    返り値型 関数名1(引数型 引数名);
public:
    クラス名();
    ~クラス名();
    変数型 変数名1;
    返り値型 関数名2(引数型 引数名);
};
クラス名::クラス名()
{
    処理;
}
クラス名::~クラス名()
{
    処理;
}
返り値型 クラス名::関数名1(引数型 引数名)
{
    処理;
}
返り値型 クラス名::関数名2(引数型 引数名)
{
    処理;
}

クラスには,アクセス可能範囲があります.private:より下に宣言されたものについては,クラスのメンバ関数内でしか扱うことができません.public:より下に宣言されたものについては,どこからでもアクセスが可能です.このようなprivateやpublicのことをアクセス指定子といいます.また,「クラス名()」と宣言されているものがありますが,これをコンストラクタといい,クラス型の変数を宣言したときに実行されるものになります.「~クラス名()」はデストラクタといい,クラス型の変数を解放したときに実行される処理になります.不要な場合には,省略することが可能です.メンバ関数の宣言は,プロトタイプ宣言と同様にして宣言することができます.コンストラクタやデストラクタ,メンバ関数の定義については,クラス定義のあとに,「クラス名::メンバ関数」といようにして定義することができます.例えば,先ほど構造体でのHuman型を拡張したものを考えてみます.

#include <iostream>
class Human{
public:
    ~Human();
    char name[20];
    double weight;
    double height;
    int age;
    void Say();
};
Human::~Human()
{
}
void Human::Say()
{
    std::cout << "My name is " << this->name << std::endl;
}
int main()
{
    Human h1;
    std::cin >> h1.name >> h1.weight >> h1.height >> h1.age;
    std::cout << "Name: "<< h1.name << std::endl;
    std::cout << "Weight: " << h1.weight << std::endl;
    std::cout << "Height: "<< h1.height << std::endl;
    std::cout << "Age: " << h1.age << std::endl;
    h1.Say();
}

メンバ関数内の処理で,メンバ変数にアクセスするときには「this->メンバ変数名」と記述します.最近のC++のバージョンでは「this->」について,省略が可能にもなっています.また,メンバ関数は,メンバ変数と同様に「クラス型変数.メンバ関数」というようにしてアクセスできます.上記の例で,デストラクタを定義していますが,デストラクタを定義することによって,クラス型の変数を解放する処理が自動的に挿入されることになります.今回は,privateなメンバ変数やメンバ関数がありませんでしたが,privateなこれらがあった場合には,main関数内でのアクセスはできません.

構造体とクラスの違い

実はC++の構造体ではクラスと同様にメンバ関数を持つことができます.初期のアクセス権限が異なります.structの場合,アクセス指定子を省略した場合,メンバ変数・関数がpublicになります.一方,classでは,アクセス指定子を省略した場合,メンバ変数・関数がprivateになります.違いはこれだけしかありませんが,ごちゃまぜにするとややこしいことになるので,メンバ変数しか持たないようなものは構造体,メンバ関数をもつものはclassというように使い分ける方がよいでしょう.

コンストラクタとデストラクタ

クラスの説明中にコンストラクタとデストラクタについて述べましたが,動作を確認してみましょう.

#include <iostream>
class Test{
public:
    Test();
    ~Test();
};
Test::Test()
{
    std::cout << "Create Test class" << std::endl;
}
Test::~Test()
{
    std::cout << "Remove Test class" << std::endl;    
}
int main()
{
    Test test;
    std::cout << "Processing" << std::endl;
}

上記のプログラムを実行してみてください.「Create Test class」「Processing」「Remove Test class」の順で表示されればOKです.Test test;が実行されたときに,コンストラクタが呼び出され,プログラム終了時にデストラクタが呼び出されていることがわかると思います.プログラム終了時に,変数はすべて解放されるのでデストラクタが呼び出されます.

構造体とクラスのポインタ型

構造体やクラスについてもポインタ型を宣言することができます.

#include <iostream>
class Human{
public:
    ~Human();
    char name[20];
    double weight;
    double height;
    int age;
    void Say();
};
Human::~Human()
{
}
void Human::Say()
{
    std::cout << "My name is " << this->name << std::endl;
}
int main()
{
    Human *h1 = new Human();
    (*h1).Say();
}

ポインタ変数のデータを参照するときには,変数の前に「*」を付けなくてなりませんでした.構造体やクラスのポインタ変数についても同様です.しかし,「(*変数名).メンバ変数」というように記述しなければなりません.これを,何回も記述するのは面倒です.そこでは,アロー演算子「->」というものを使用します.アロー演算子を用いると「変数名->メンバ変数」のように記述することができます.つまり,「(*h1).Say();」と記述していた部分を「h1->Say();」と記述しても同じ動作をすることになります.また,メンバ関数が自身のメンバ変数にアクセスする際に「this->メンバ変数」と記述すると説明しましたが,thisは自身のアドレスを表すポインタ型になります.

// どちらも同じ動作
(*h1).Say();
h1->Say();

演習

・今回の例で用いたHuman型クラスを用いて,10人のデータを入力させ,身長順にすべての情報を表示するプログラムを作成してください.