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

C++でオブジェクト指向プログラミング
―― 第10章 クラス〜オブジェクト指向プログラミング(後編) ――

WINGSプロジェクト 矢吹 太朗(監修 山田 祥寛)
2010/06/16
Page1 Page2

本コーナーは、日経BPソフトプレス発行の書籍『文法からはじめるプログラミング言語Microsoft Visual C++入門』の中から、特にInsider.NET読者に有用だと考えられる章や個所をInsider.NET編集部が選び、同社の許可を得て転載したものです。基本的に元の文章をそのまま転載していますが、レイアウト上の理由などで文章の記述を変更している部分(例:「上の図」など)や、図の位置などを本サイトのデザインに合わせている部分が若干ありますので、ご了承ください。『文法からはじめるプログラミング言語Microsoft Visual C++入門』の詳細は「目次情報ページ」もしくは日経BPソフトプレスのサイトをご覧ください。

ご注意:本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。

10.2 標準C++におけるオブジェクト指向プログラミング

 この節では、クラスを継承して新しいクラスを作成する方法を紹介します。継承には仮想関数というしくみが用意されており、これを利用するとクラスのインターフェイスと実装を分離し、インターフェイスを対象にしたプログラムを書くことができるようになります。継承と仮想関数を利用するプログラミングがオブジェクト指向プログラミングです。

10.2.1 継承

 次のようなクラスPersonがあるとしましょう。これは一般的な人を表すためのクラスで、名前(name)と年齢(age)というフィールドと、食べる(eat)、表示する(show)というメソッドを持っています。

class Person
{
  string name;
  int age;
public:
  Person(string name, int age) : name(name), age(age) {}
  void eat() { cout<<name<<": eat()\n"; }
  void show() { cout<<name<<" ("<<age<<")\n"; }
};
[サンプル]10-inheritance1.cpp

 このクラスPersonを継承して、学生を表すためのクラスStudentを作ります。そのようなことができるのは、「学生は人である」というis-a関係が成立するためです。クラスを継承で作るかどうかは、それがis-a関係かどうかで判断してください。is-a関係でないものを継承で結び付けるべきではありません。

 継承の元になるクラスを基底クラス、継承してできたクラスを派生クラスと呼びます。両者の関係は、スーパークラスとサブクラス、あるいは親クラスと子クラスとも呼ばれます。

 継承には次のような構文を使います。

class クラス名 : public 基底クラス名
{
  追加の宣言
}
[構文]継承

 クラスPersonのメンバに加えて、新たにID番号(id)というフィールドと、勉強する(study)というメソッドを追加したクラスStudentの定義は次のようになります。クラスStudentの定義には、クラスPersonとの違いを書くだけです。フィールドnameやageの宣言や、メソッドeat()やshow()の定義を繰り返す必要はありません。図10-5のように、派生クラスの定義で必要なのは、基底クラスと違う部分だけです。

図10-5 派生クラスで定義すべきこと

class Student : public Person
{
  int id;
public:
  Student(string name, int age, int id) : Person(name, age), id(id) {}
  void study() { cout<<id<<": study()\n"; }
};
[サンプル]10-inheritance1.cpp

 この例では、名前と年齢、IDを引数とするコンストラクタを定義していますが、名前と年齢の初期化はPerson(name, age)のような初期化子によって、基底クラスで行うことにしています。

 2つのクラスPersonとStudentを使う例を以下に示します。

int main()
{
  Student s("Hanako", 22, 1);
  s.show(); //出力値:Hanako (22)
  s.eat(); //出力値:Hanako: eat()
  s.study(); //メソッドstudy()を持つのはStudentだけ
  //出力値:1: study()

  Person p("Taro", 32);
  p.show(); //出力値:Taro (32)
  p.eat(); //出力値:Taro: eat()
  //p.study();//エラー(メソッドstudy()はPersonのメンバではない)
}
[サンプル]10-inheritance1.cpp

10.2.2 アクセス制御

 フィールドnameやidはPersonのprivateなメンバなので、Studentのメソッドからアクセスすることはできません。これでは不便なので、Personの定義を次のように変更して、Studentからもnameやidを操作できるようにしましょう。

class Person
{
protected:
  string name;
  int age;
public:
  Person(string name, int age) : name(name), age(age) {}
  void eat() { cout<<"eat()\n"; }
  void show() { cout<<name<<" ("<<age<<")\n"; }
};
[サンプル]10-inheritance2.cpp

 このように、protectedにしたメンバには、派生クラスからもアクセスできます。もちろん、アクセスできるようにするだけならpublicにしてもよいのですが、クラスの内部はなるべく外部から見えないようにしておくべきなので、protectedの方がよいでしょう。

 名前(name)をprotectedにしたので、次のようにStudentのメソッドstudy()で利用できるようになります。

  void study() { cout<<name<<" (id:"<<id<<"): study()\n"; }
[サンプル]10-inheritance2.cpp

 Studentオブジェクトを作ってメソッドStudy()を呼び出して、フィールドnameにアクセスできることを確認できます。

Student s("Hanako", 22, 1);
s.study(); //出力値:Hanako (id:1): study()(変更された)
[サンプル]10-inheritance2.cpp

 基底クラスPersonと派生クラスStudentoの関係をUMLクラス図で描くと図10-6のようになります。UMLクラス図では、protectedメンバには「#」を付けます。

図10-6 基底クラスPersonと派生クラスStudent


 INDEX
  [書籍転載]文法からはじめるプログラミング言語Microsoft Visual C++入門
  C++でオブジェクト指向プログラミング
  1.継承/アクセス制御
    2.仮想関数/純粋仮想関数/テンプレートによる暗黙的なインターフェイス指定

インデックス・ページヘ 「文法からはじめるプログラミング言語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 記事ランキング

本日 月間