|
書籍転載
文法からはじめるプログラミング言語Microsoft Visual C++入門
C++でオブジェクト指向プログラミング
―― 第10章 クラス〜オブジェクト指向プログラミング(後編) ――
WINGSプロジェクト 矢吹 太朗(監修 山田 祥寛)
2010/06/16 |
|
本コーナーは、日経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 |
Insider.NET 記事ランキング
本日
月間