Objective-Cの継承とポリモーフィズム



Inheritance Polymorphism Objective C



オブジェクト指向プログラミングが主流のプログラミングになる理由は、その継承とポリモーフィズムから切り離せません。オブジェクト指向言語である限り、継承とポリモーフィズムをサポートします。もちろん、さまざまなOOP言語には独自の特性があります。 OCはJavaに似ており、多重継承をサポートしていませんが、OOP言語C ++は多重継承をサポートしています。 OCが多重継承をサポートしない理由については後で説明します。

相続といえば、「西方の旅」の言葉を引用して相続を説明した本を思いついた。 「人は母親から生まれ、鬼は鬼から生まれる!」と、中の唐三蔵もオブジェクト指向プログラミングを学んだと思います。たぶん、彼らには4人の男性と女性がいて、アルゴリズムの紹介をしたり、OOPプログラミング、データ構造などの本について話したりするために西に行きます。人間も悪魔も動物に属していますが、それぞれに独自の特徴があり、それぞれに違いがあります。動物は父親であり、人と悪魔はサブクラスです。継承の目的は、コードの冗長性、つまりDRYの原則を減らすことです(繰り返してはいけません)。



Objective-Cでは、superは直接の親クラスへのポインターであり、selfはそれ自体へのポインターであり、selfはjavaのthisポインターと同等です。 OCでクラスを作成する場合、@ interfaceで宣言されていないメソッドを@implementationで定義できますが、このメソッドはプライベートであり、クラスの実装でのみ使用されます。


Objectiv-CのほとんどすべてのクラスはNSObjectクラスを継承しており、NSObjectクラスには強力なメソッドがたくさんあります。以下では、NSObjectクラスのさまざまなメソッドについて説明します。



1. +(void)loadこのメソッドは、クラスがランタイム環境にロードされるときに呼び出されます。

テスト:テストするサブクラスのloadメソッドを書き直します。 loadメソッドを書き直すときは、mianメソッドでオブジェクトをインスタンス化する必要はありません。

クラスがロードされると、loadは呼び出されません。loadはクラスメソッドであり、クラスから直接呼び出すことができます。



/ / Rewrite the load method in NSObject +(void) load { NSLog (@'ObjectTest's load method is called!!') }
演算結果:
2014-07-30 08:58:31.704 HelloOC[550:303] The load method in ObjectTest is called! !

2. +(void)initializeこのメソッドは、クラスが最初にクラスを使用するときに呼び出され、2回目は呼び出されません。

テスト:初期化メソッドを書き直します

/ / Rewrite the initialize method, will be called when the class is first used +(void) initialize { NSLog(@'initialize method is called (class is instantiated for the first time)!') }
演算結果:
2014-07-30 09:27:53.767 HelloOC[624:303] The load method is called! ! 2014-07-30 09:27:53.769 HelloOC[624:303] The initialize method is called (the class is instantiated for the first time)!

3. +(id)alloc:すでに割り当てられているメモリオブジェクトを返します-(id)init:メモリが割り当てられているインスタンスを初期化します新しい呼び出しallocとinitを同時に呼び出します

デモ:Object * object = [[Object alloc] init]

サブクラスのallocを書き換えて、操作を監視できます。

/ / Rewrite the alloc method +(id) alloc { NSLog (@'alloc function is called') return [super alloc] }

/ / Rewrite init -(id) init { NSLog (@'init is called') self = [super init] return self }

テストメソッド1つはallocとinitを使用してクラスをインスタンス化し、もう1つはnewを使用してクラスをインスタンス化します。

/ / The first time using the ObjectTest class ObjectTest *o1 = [[ObjectTest alloc] init] / / The first time using the ObjectTest class ObjectTest *o2 = [ObjectTest new]
演算結果:
2014-07-30 09:59:58.991 HelloOC[689:303] The load method is called! ! 2014-07-30 09:59:58.993 HelloOC[689:303] The initialize method is called (the class is instantiated for the first time)! 2014-07-30 09:59:58.993 HelloOC[689:303] alloc function is called 2014-07-30 09:59:58.993 HelloOC[689:303] init was called 2014-07-30 09:59:58.994 HelloOC[689:303] alloc function is called 2014-07-30 09:59:58.994 HelloOC[689:303] init was called

4 .-(void)deallocは、オブジェクト自体が占有していたメモリを解放します

5 .-(Class)classまたは+(Class)classは、現在のオブジェクトのクラスを返します-(Class)superclassまたは+(Class)superclassは、現在のクラスの親クラスを返します

/ / Returns the class corresponding to the current object NSString *className =(NSString *) [self class] NSLog (@'%@ class display method', className) / / Returns the parent class corresponding to the current object NSString *superClassName = (NSString *) [self superclass] NSLog (@'%@class's parent class is %@', className, superClassName)

6、-(BOOL)isKindOfClass:(Class)aClassは、インスタンスがオブジェクトのクラスまたはサブクラスに属しているかどうかを判別します

ケースコードは次のとおりです。

//isKindOfClass usage BOOL b = [o2 isKindOfClass:[ObjectTest class]] if (b == YES) { NSLog (@'o2 is an object of the ObjectTest class') }

7 .-(BOOL)isMemberOfClass:(Class)aClassインスタンスがクラスに属しているかどうかのみを判別でき、親クラスに属しているかどうかを判別できません。

//isMemberOfClass BOOL result = [o2 isMemberOfClass:[NSObject class]] if (result == NO) { NSLog(@'isMemberOfClass cannot determine if it is an object of the NSObject subclass') }

8 .-(NSString *)descriptionデバッグを容易にするために、オブジェクトの説明を文字列形式で返します

//description NSString *descript = [o2 description] NSLog(@'%@', descript)

出力結果:

9 .-(NSUInteger)hashオブジェクトのハッシュ値を返します

//hash usage NSUInteger hash = [o2 hash] NSLog(@'%p', hash)

出力:2014-07-30 11:40:35.685 HelloOC [1130:303] 0x100107b70

10 .-(BOOL)isEqual:(id)object2つのオブジェクトが同じかどうかを比較します。デフォルトでは、比較にアドレスを使用し、ハッシュ値は同じである必要があります。

//isEqual usage NSString *str1 = @'111' NSString *str2 = str1 if ([str2 isEqual:str1] == YES) { NSLog(@'str2 == str1') } else { NSLog(@'str2 != str1') }

Objective-Cの継承

継承はis-aの関係です。たとえば、猫は動物であり、次に動物は親であり、猫は動物のサブクラスです。サブクラスには、親クラスのプロパティと動作、および独自のプロパティと動作があります。つまり、「親はより一般的で、サブクラスはより具体的です」。クラスの継承を第2世代のクラスで説明します。

1.最初に金持ちのクラスを定義します

コードの説明:

1. @protectedアクセス権限を持つ3つのプロパティ、@ propertyに加えてgetterメソッドとsetterメソッドを持つ3つのプロパティを宣言します

2.クラスの便利な初期化メソッドと便利なコンストラクターを作成します

3.金持ちのためのクレジットカードの方法を定義する

// // Richer.h // HelloOC // // Created by ludashi on 14-7-29. // Copyright (c) 2014 ludashi. All rights reserved. // #import @interface Richer : NSObject { @protected NSString *name int age NSString *gender } / / Define the rich person's name, age, gender, and provide them with getter and setter methods @property (copy, nonatomic) NSString *name @property (assign, nonatomic) int age @property (copy, nonatomic) NSString *gender / / Define a convenient initialization method -(id) initWithName : (NSString *)vName AndAge : (int)vAge AndGender : (NSString *)vGender / / Define the convenience constructor +(id) richerWithName : (NSString *)vName AndAge : (int)vAge AndGender : (NSString *)vGender / / Define the card method -(void) poss @end

2.金持ちのための実装コードを書く

コードの説明:

1. @ synthesizeを使用してgetterメソッドとsetterメソッドを実装します

2.便利な初期化メソッドを実装し、リッチペアレントの直接の親クラスを[superinit]で初期化します。これはNSObjectです。

3.コンビニエンスコンストラクターを使用して、インスタンス化および初期化されたオブジェクトを返します

#import 'Richer.h' @implementation Richer / / Implement the getter and setter methods @synthesize name, age, gender / / Implement the convenience initialization function -(id) initWithName : (NSString *)vName AndAge : (int)vAge AndGender : (NSString *)vGender { if (self = [super init]) { self->name = vName self->age = vAge self->gender = vGender } return self } / / Implement the convenience constructor +(id) richerWithName:(NSString *)vName AndAge:(int)vAge AndGender:(NSString *)vGender { Richer *richer = [[Richer alloc] initWithName:vName AndAge:vAge AndGender:vGender] return richer } / / Implement the card method -(void) poss { NSLog(@'%@You have money, please brush it', name) }@end

3.豊富な第2世代のクラスを作成します。金持ちの第二世代と金持ちの人々は、多くの同様の特性と方法を持っています。そのため、金持ちの第2世代は金持ちの人間から継承し、対応するプロパティとメソッドを追加して、書き直す必要のあるメソッドを書き直します。

コードの説明:

1.豊富な第2世代クラスに新しい趣味の属性を追加します

2.リッチな第2世代のための新しいメソッドを追加します

#import 'Richer.h' @interface Richer2nd : Richer //Richer2nd inherits all the methods of Richer / / Add a new attribute for the rich second generation @property (copy, nonatomic) NSString *hobby / / Convenience initialization function -(id) initWithName : (NSString *) vName AndAge : (int)vAge AndGender : (NSString *) vGender AndHobby : (NSString *)vHobby //Write a convenience constructor for Richer2nd +(id)richer2ndWithName : (NSString *) vName AndAge : (int)vAge AndGender : (NSString *) vGender AndHobby : (NSString *)vHobby / / Add hobby method -(void) myHobby @end

4.さまざまな方法の実装

コードの説明:

1.便利な初期化メソッドを作成するときに、superを使用して親クラスの便利な初期化メソッドを呼び出し、継承された親クラスのメソッドを初期化します。

2. selfを使用して、新しく追加されたプロパティを初期化します


#import 'Richer2nd.h' @implementation Richer2nd / / Implement the property's getter and setter methods @synthesize hobby / / Write a convenient initialization function, reuse the convenience initialization method of the parent class -(id)initWithName:(NSString *)vName AndAge:(int)vAge AndGender:(NSString *)vGender AndHobby:(NSString *)vHobby { if (self = [super initWithName:vName AndAge:vAge AndGender:vGender]) { self->hobby = vHobby } return self } / / Write a convenience constructor +(id)richer2ndWithName:(NSString *)vName AndAge:(int)vAge AndGender:(NSString *)vGender AndHobby:(NSString *)vHobby { Richer2nd *richer = [[Richer2nd alloc] initWithName:vName AndAge:vAge AndGender:vGender AndHobby:vHobby] return richer } / / Rewrite the card method -(void)poss { [super poss] NSLog (@'I am rich second generation, my dad has money, I will brush!') } / / Add a new method -(void) myHobby { NSLog (@'I am rich second generation%@, I like %@', name, hobby) } @end

5.以下は上記のコードの結果です

2014-07-30 08:38:12.956 HelloOC[483:303] If you have money, you can brush it. 2014-07-30 08:38:12.957 HelloOC[483:303] BILL`s son, you can brush it if you have money. 2014-07-30 08:38:12.958 HelloOC[483:303] I am rich second generation, my dad has money, I will brush! 2014-07-30 08:38:12.958 HelloOC[483:303] I am a rich second generation BILL`s son, I like the car very much.

Objective-Cのポリモーフィズム

ポリモーフィズムは、同じメソッドに応答するさまざまなオブジェクトに対する単純に異なる応答です。 OCでは、動的型IDはポリモーフィズムを実装する方法です。 idは、任意のデータ型に変換できる一意のデータ型です。豊かで豊かな第二世代はこのように定義することができます。

id richer = nil //Test rich humans richer = [Richer richerWithName:@'Bill' AndAge:40 AndGender:@'Man'] [richer poss] / / Test the class of the rich second generation Richer = [Richer2nd richer2ndWithName:@'BILL`s son' AndAge:16 AndGender:@' ' AndHobby:@' '] [richer poss] [richer myHobby]

上記のプログラムの出力は、継承部分の結果と一致しています

ポリモーフィズムの別の例:動物は親クラスであり、子クラスにはCatとDogがあり、オブジェクトをインスタンス化するときに子はそれぞれ親クラスのeatメソッドをオーバーライドします。次のメソッドを使用できます。

Animal *animal = nil // instantiate the cat's object animal = [Cat new] [animal eat] // instantiate the dog's object animal = [Dog new] [animal eat]

オブジェクト指向プログラミングにおけるOCPの原則とLSPの原則

OCP:オープンクローズドプリンシパル、エクステンションにオープン、モディフィケーションにクローズ

LSP:任意の基本クラスが表示される可能性があるLieの置き換えの原則では、サブクラスが表示される必要があります。