連載
» 2009年03月06日 00時00分 UPDATE

Cocoaの素、Objective-Cを知ろう(6):コードをもっとオブジェクティブに (1/4)

iPhone用アプリケーション開発で注目を集める言語「Objective-C」。C++とは異なるC言語の拡張を目指したこの言語の基本を理解しよう(編集部)

[竹下肯己,株式会社 qnote]

 第4回「変数のデータ型や文字列の扱いを理解しよう」、第5回「配列とループ処理を理解しよう」と、日々のコーディングに必要となる要素について、Foundation内のクラスの紹介を中心に解説しました。

 今回は、Objective-Cのオブジェクト指向言語としての特徴をより深く理解するための話題を取り上げたいと思います。

 オブジェクト指向に基づいた体系的なクラス設計をすることで、コードの重複を排除し、効率的でカスタマイズ性の高いプログラムを開発することができます。Foundationのライブラリや、GUIを駆使したCocoaのアプリケーションも、ここで紹介するような仕組みを有効に活用することで成り立っています。

クラスの継承

 すでに何度か言及していますが、オブジェクト指向の言語では、あるクラスを継承する形で新たなクラスを定義できます。既存クラスの属性(インスタンス変数)や機能(メソッド)を引き継いで、新たな属性や機能などの差分だけを定義します。同じ機能で振る舞いを変えたい場合には、同名のメソッドをオーバーライド(上書き)します。

 このとき、継承する側のクラスから見た継承元の既存クラスをスーパークラス、逆に継承される側から見た新たなクラスをサブクラスと呼びます。便宜的に親クラス子クラスなどと呼ばれることもあります。

 また、NSObjectはすべてのクラスの直接または間接的なスーパークラスとなるため、特にルートクラスとも呼ばれます。

 例えば、プログラムの機能を作成する場合に、基本的な機能は共通で、少しずつ振る舞いの異なるサブ機能をクラスとして展開していきたい場合には、継承の仕組みが便利です。以下に、継承を利用したごく単純な例を見てみましょう。





a
b

b
b



b
b





a





c




a

d



d









b
b


b
c


b
b
d



#import <Foundation/Foundation.h>
#import <stdio.h>

// 父親クラス
@interface Father : NSObject {
    NSString *job;
}
@property (retain) NSString *job;
- (void)work;
@end

@implementation Father
@synthesize job;
- (void)work {
    printf("%s\n", [job UTF8String]);
}
@end

// 長男クラス
@interface EldestSon : Father {
}
@end

@implementation EldestSon
- (void)work {
    printf("%s and smoking\n", [job UTF8String]);
}
@end

// 次男クラス
@interface SecondSon : Father {
}
- (void)cook;
@end

@implementation SecondSon
- (void)cook {
    printf("cooking\n");
}
@end


int main(void) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        Father *father = [[Father alloc] init];
        [father setJob:@"accounting"];
        [father work];

        EldestSon *eldestSon = [[EldestSon alloc] init];
        [eldestSon setJob:@"programming"];
        [eldestSon work];

        SecondSon *secondSon = [[SecondSon alloc] init];
        [secondSon setJob:@"designing"];
        [secondSon work];
        [secondSon cook];

    [pool drain];
    return 0;
}
main.m

 あるクラスを継承したいとき、@interfaceのクラス宣言部分には、クラス名に続けて「 : スーパークラス名」を記述します。スーパークラスとして指定できるクラス名は1つだけです。

 上記の例では、父親を表すFatherクラスと、長男・次男を表すEldestSonクラス・SecondSonクラスを定義しています。Fatherクラスは、この構造の中では最も上位に属するためNSObjectを継承し、EldestSonクラス・SecondSonクラスはFatherクラスを継承しています(コード中のaの部分)。

 父親・長男・次男はそれぞれに仕事を持っています。従って、職業を表すjobというインスタンス変数およびそのアクセサをFatherクラスに定義しておけば、そのサブクラス(長男や次男)でもそのまま利用できます。また、実際に仕事を行うworkメソッドも、典型的な実装はFatherクラスに定義しています(コード中のbの部分)。

 長男は、仕事の合間にタバコを吸う習慣があります。よってEldestSonクラスでは、同じ名前のworkメソッドを定義(オーバーライド)して、その振る舞いを変えています(コード中のcの部分)。

 一方、次男は職業が違っていても仕事時の振る舞いは父親と変わらないので、workメソッドはFatherクラスの定義をそのまま利用しています。また、次男は仕事とは関係なく料理をする習慣があるので、新たにcookというメソッドを定義しています。「仕事をする」というスーパークラスの機能を拡張し、「料理をする」という機能を付加しているわけです(コード中のdの部分)。

 継承によるクラス構造をどう設計するかは、そのクラス群の用途によっても変わってきますが、サブクラス群で共通となる属性や機能はなるべくスーパークラス側に定義し、必要なときだけサブクラスで上書きしたり追加定義したり、といった考え方が基本となるでしょう。

       1|2|3|4 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。