見出し画像

C++ 再入門 その6 コンストラクタで初期化する

前回、構造体のように複数のデータをまとめて扱う方法として、C++ではクラスというものがあることを説明しました。クラスが構造体と違うところとして、クラスに属する関数を書くことができるまでは簡単に説明しましたが、その関数の中にはクラスの初期化を担う「コンストラクタ」と呼ばれる特別な関数があります。

class product {
public:
  // コンストラクタ
  product() {
    name = "";
    price = 0;
    sku = "";
  }

  // クラスに属する関数
  void repr(void) {
    cout << name << "," << price <<  "," << sku << endl;
  }

  // クラスが持っている変数
  string name;
  unsigned int price;
  string sku;
};

このようにクラス名と同じ名前の関数を定義すると、それはコンストラクタと呼ばれる特別なクラス関数になります。この関数は、このクラスの変数が作られる時に必ず呼び出される関数で戻り値はありません。

void main() {
  product pd;  // ここでコンストラクタが呼び出される
  pd.repr();    // コンストラクタで初期化された値を確認する
}

,0,

コンストラクタで書記されていることを確認

変数を宣言すると、そこでコンストラクタが自動的に呼び出されるので、クラスの持つ変数が初期化されていることがわかります。せっかくですから、初期化の際に初期値も設定できると便利ですよね。もちろん、そのような書き方も出来ます。

// 引き数で初期化するコンストラクタ(クラス定義に書くもの)
product(string init_name, unsigned int init_price, string init_sku) {
  name = init_name;
  price = init_price;
  sku = init_sku;
}
void main() {
  product pd("pencil", 30, "P001002");  // ここでコンストラクタが呼び出される
  pd.repr();                       // コンストラクタで初期化された値を確認する
}

pencil,30,P001002

コンストラクタで初期化されている

ちゃんと引き数で渡した値で初期化出来ました。コンストラクタは引き数の型を変えればいくつも書くことが出来て、初期化の際にカッコで渡した引き数の数と型で対応するコンストラクタが選ばれます。このようにコンストラクタの仕組みがあることで、初期化を忘れずに行うことが出来ます。逆に言うとコンストラクタが定義されていれば、変数の宣言は単なる宣言ではなく、その場所で初期化が実行される実行文になるわけです。コンストラクタは普通に関数なので変数の初期化だけではなく、条件判断なども必要であれば、もちろん書けるわけです。

さて、同じ名前の関数であっても引き数の数と型が異なれば、いくつも書くことが出来るというのはC言語には無い芸当で(C言語では同じ名前で異なる引き数の関数を定義するとエラーになる)、これはコンストラクタ以外の普通の関数でも同じです。これが関数の「多重定義」であり「オーバーロード」と呼ばれる仕組みです。次回は、その辺りをもう少し調べてみましょう。


さて、stringという名前がアチラコチラで登場していますが「char[]の仲間だとすればポインタで渡さなくて良いの?」と思う方もいるかもしれません。実はstringはクラスでもなくてテンプレートという仕組みで実装されていたりしますし、C++ではポインタではなくて参照という仕組みを使うのですが、いずれにせよ string はとても賢くて、コピーしても strcpy のように実体(文字列が格納されているメモリ自身)をコピーするのではなく、殆どの場合は同じ実体を指したまま使えるようにしてくれます。という訳で、あまり気にせずに string を使っても大丈夫です。

また、コンストラクタと対になるものとして、デストラクタというのも存在します。クラスの変数を宣言しコンストラクタが呼び出され、その後、その有効範囲が終わった時点で自動的に呼ばれるのがデストラクタです。コンストラクタで malloc などで動的に確保したメモリは、デストラクタで free できるという訳です。コンストラクタを書いたら必ずデストラクタが必要になるというわけでもありませんし、デストラクタはコード上で明示的に呼ばれないことが普通なので、どのタイミングで呼び出されるのかは実に難しくて、その辺りは後回しにしましょう。

ヘッダ画像は、以下のものを使わせていただきました。
https://commons.wikimedia.org/wiki/File:ISO_C%2B%2B_Logo.svg
Jeremy Kratz - https://github.com/isocpp/logos, パブリック・ドメイン, https://commons.wikimedia.org/w/index.php?curid=62851110による

#プログラミング講座 #クラス #コンストラクタ #初期化 #多重定義 #オーバーロード

この記事が気に入ったらサポートをしてみませんか?