書籍転載
文法からはじめるプログラミング言語Microsoft Visual C++入門

C++のクラスをマスターしよう(前編)
―第10章 クラス〜オブジェクト指向プログラミング(前編)―

WINGSプロジェクト 矢吹 太朗(監修 山田 祥寛)
2010/05/19

10.1.6 コンストラクタ

 オブジェクトを生成する際には、コンストラクタという特殊なメソッドが呼び出されます。コンストラクタは次のように定義します(宣言と定義を分けることもできます)。普通のメソッドと違って、コンストラクタには戻り値がないことに注意してください。

クラス名(パラメータリスト)
{
  文
};
[構文]コンストラクタの定義

 引数のないコンストラクタをデフォルトコンストラクタ(既定のコンストラクタ)と呼びます。プログラマがコンストラクタを定義しない場合には、空のデフォルトコンストラクタがコンパイラによって生成されます。つまり、10.1.2項のクラスPersonの定義は、次のコードと同じです。

struct Person
{
  string name;
  int age;

  //デフォルトコンストラクタ
  Person() {} //この記述がないと、コンパイラが自動生成する。
};

 デフォルトコンストラクタを次のように実装すれば、オブジェクトが生成されるときにメッセージが表示されます。

#include <iostream>
using namespace std;

struct Person
{
  string name;
  int age;

  Person() { cout<<"オブジェクトが生成された\n"; }
};


int main()
{
  Person x;
  //出力値:オブジェクトが生成された
}
[サンプル]10-constructor1.cpp

 コンパイラによって自動生成されるのは、デフォルトコンストラクタだけではありません。次のようにクラスを定義したとしましょう。

struct Person
{
  string name;
  int age;
};
[サンプル]10-defaultmethods.cpp

 このコードをコンパイルすると、デフォルトコンストラクタの他に、次のようなメソッドが自動生成されます*4

  • コピーコンストラクタ:別のオブジェクトをコピーして新しいオブジェクトを生成する
  • 代入演算子:オブジェクトを別のオブジェクトで上書きする
  • デストラクタ:オブジェクトを削除する際に呼び出される(既定では機能はない)
*4 C++0x では、これらのメソッドの自動生成を禁止することができるようになる予定です。

 次のような自明に見える操作ができるのは、自動生成されたこれらのメソッドのおかげです。

Person taro; //デフォルトコンストラクタの利用
taro.name="Taro";
taro.age=32;

Person a(taro); //コピーコンストラクタの利用
//Person a=taro; //でもよい
cout<<a.name<<endl;//出力値: Taro

Person b;
b=a; //代入演算子の利用
cout<<b.name<<endl;//出力値: Taro
[サンプル]10-defaultmethods.cpp

 このPersonのような簡単なクラスの場合には、自動生成されるメソッドで十分なのですが、クラスによっては自動生成されるメソッドでは機能が不十分だったり、動作が期待どおりではないことがあります。そのような場合には、これらのメソッドを自分で定義し直します。

 たとえば、オブジェクトの生成と同時に名前と年齢を初期化するようなコンストラクタが必要な場合には、次のように自分で定義しなければなりません。

#include <iostream>
#include <string>
using namespace std;

struct Person
{
  string name;
  int age;

  //名前と年齢を引数に持つコンストラクタ
  Person(string name, int age)
  {
    this->name=name;
    this->age=age;
  }

  //デフォルトコンストラクタを自分で実装する
  Person() {}
};

int main()
{
  Person taro("Taro", 32); //コンストラクタの利用
  cout<<taro.name<<endl; //出力値: Taro

  Person p; //デフォルトコンストラクタを利用
  Person people[5]; //デフォルトコンストラクタを利用
}
[サンプル]10-constructor2.cpp

 このコードでは、名前と年齢を引数に持つコンストラクタを実装しています。このコンストラクタでは、this->name=name;などとして、フィールドにパラメータを代入しています。thisは自分自身(Personオブジェクト)を指すポインタです。フィールドとパラメータの名前が違う場合には、this->という記述は不要ですが、この例ではどちらもnameなので、区別できるようにフィールドは単なるnameではなくthis->nameとしています。フィールド名を_nameのようにしておいてもよいでしょう。もちろん、コンストラクタの宣言や定義をPerson(string s, int a)のようにすれば名前は重複しませんが、パラメータの意味がわかりにくくなってしまいます。

 独自のコンストラクタを定義すると、コンパイラはデフォルトコンストラクタを自動生成しなくなることに注意してください。ですから、引数なしでオブジェクトを生成したい場合や、オブジェクトの配列を生成したい場合には、デフォルトコンストラクタを自分で実装しなければなりません。

 実は、この例のnameやageの設定方法には改善の余地があります。このリストのコンストラクタで行われているのは、初期化ではなく代入です。つまり、一度空のフィールドnameが生成されてから、パラメータの値が代入されるので、効率が悪くなるかもしれないのです(フィールドageは組み込みデータ型なので、初期化と代入に違いはありません)。

 フィールドを初期化するためには、コンストラクタの定義において、次のようなコンストラクタ初期化子を使います。

クラス名(パラメータリスト) : フィールド名(値),...
[構文]コンストラクタ初期化子

 先の例のコンストラクタは、次のように書くべきでした。これでnameとageが初期化されます。

Person::Person(string name, int age) : name(name), age(age) {}

 初期化と代入の違いは、後で紹介するコピーコンストラクタと代入演算子を比較するとよくわかります。


 INDEX
  [書籍転載]文法からはじめるプログラミング言語Microsoft Visual C++入門
  C++のクラスをマスターしよう(前編)
    1.クラスとは/クラスの生成
    2.メソッド/静的メンバ/アクセス制御
  3.コンストラクタ
    4.デストラクタ/デストラクタの役割
    5.リソース確保は初期化である

インデックス・ページヘ 「文法からはじめるプログラミング言語Microsoft Visual C++入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間