2

そのように初期化するオブジェクトがあると仮定します

- (void)doInit
{
    NSLog(@"In BaseClass init");
}

- (id)init
{
    self = [super init];
    [self doInit];

    return self;
}

同様の方法で開始されるサブクラスがあります

- (void)doInit
{
    NSLog (@"In SubClass init");
}

- (id)init
{
    self = [super init];
    [self doInit];

    return self;
}

子クラスのインスタンスを作成すると、次の出力が表示されます。

In SubClass init
In SubClass init

本当に、私が起こるつもりだったのは

In BaseClass init
In SubClass init

doInit をマークして、オーバーライドしてはならないこと、またはサブクラスのすべてのメソッドに一意の名前を作成する必要があることを示す方法はありますか?

以前にこの問題に出くわしたことがなかった理由は完全にはわかりませんが、どうぞ。

編集:

なぜこれが起こっているのか理解しています。基本クラスがオーバーライドされた関数を呼び出せるとは思っていませんでした。

[super doInit] を呼び出すこともできません。これは、BaseClass のインスタンスの作成が引き続き機能するように、BaseClass が doInit を呼び出す必要があるためです。[super doInit] を呼び出しても、SubClass の doInit が 2 回呼び出されることになります。

答えはノーのようです。doBaseClassInit や doSubClassInit のように、各 doInit に一意の名前を付ける必要があります。

4

5 に答える 5

4

動的にバインドしたくないメソッドがある場合 (つまり、サブクラス メソッドが存在する場合にそれを呼び出したくない場合)、代わりに C 関数として実行する必要があります。したがって、代わりにこれを行うことができます:

基本クラス:

static void DoInit(BaseClass *self)
{
    NSLog(@"In BaseClass init");
}

- (id)init
{
    self = [super init];
    if (self) {
        DoInit(self);
    }
    return self;
}

サブクラスで:

static void DoInit(SubClass *self)
{
    NSLog(@"In SubClass init");
}

- (id)init
{
    self = [super init];
    if (self) {
        DoInit(self);
    }
    return self;
}

両方のDoInitメソッドが としてマークされてstaticいるため、各コンパイル単位 (.m ファイル) でのみ表示され、互いに競合しないことに注意してください。

于 2012-09-24T09:48:45.627 に答える
2

おそらく、基本クラスでこのようなことを試すことができます。initこれは、内部の実装がBaseClass実行されるたびに、の実装が呼び出されることを意味しdoInitますBaseClass

- (void)doInit
{
    NSLog(@"In BaseClass init");
}

- (id)init
{
    self = [super init];

    Class baseClass = [BaseClass class];
    SEL selector = @selector(doInit);
    IMP baseClassImplementation = class_getInstanceMethod(baseClass, selector);
    baseClassImplementation(self, selector);

    return self;
}

コメントで述べたように、それがあなたのニーズの狭さである場合、これはメッセージの送信に関連する動的なメソッドルックアップを回避するので機能するはずです。お役に立てれば!

編集:

免責事項-このような状況にある場合、それはおそらく設計の寿命の良い兆候ではありません。この手法を使用すると、今のところ使用できるようになりますが、慎重に文書化し、コードをリファクタリングして使用されないようにする方法を検討してください。このような修正は、非常に緊急の場合にのみ実際に使用することを検討してください。

于 2012-09-22T22:30:35.267 に答える
1

コンソール メッセージが表示されない理由"In BaseClass init"は、サブクラスがスーパーの doInit の実装を呼び出していないためです。

オーバーライドしたくない場合doInit、オーバーライドを回避する「最善の」方法は、このメソッドの存在を公開しないことです。ヘッダーから削除し、メソッドに一意の名前を付けて、競合が発生しないようにします。たとえば、Apple のフレームワークのプライベート メソッドの多くには、先頭にアンダースコアが付いています。したがって、たとえば、メソッド_doInitを呼び出すことができ、サブクラスが誤って独自のオーバーライド実装を作成する可能性はほとんどありません。

于 2012-09-22T21:41:43.083 に答える
1

いいえ、サブクラスがメソッドをオーバーライドするのを防ぐ強制的な方法はありません。あなたができる最善のことは、それをクラスの公開ヘッダー ファイルに入れないようにすることです。メソッドをパブリックにする必要がある場合は、メソッドのドキュメントに、オーバーライドしてはならないこと、またはサブクラスがスーパーの実装を呼び出す必要があることをメモしてください。この種の手順は、Apple 独自のクラスのドキュメントのいたるところにあります。

于 2012-09-22T21:44:14.743 に答える
0

サブクラスで doInit のベースクラス バージョンを使用する場合は、サブクラスで doInit メソッドを宣言しないでください。これが私が意味することです:

クラスA:

@interface ClassA : 

-(void) doInit;
-(id) init;

@implementation

-(void) doInit {
    NSLog(@"ClassA doInit");
}

-(id) init {
    self = [super init];

    if (self != NULL)
        [self doInit];

    return self;
}

クラスB

@interface ClassB : ClassA

-(id) init;

@implementation

-(id) init {
    self = [super init];

    if (self != NULL)
        [self doInit];

    return self;
}

また、そのクラスに実行させたい特別なコードがない限り、実際には init メソッドもオーバーライドする必要はありません。

于 2012-09-22T21:42:29.507 に答える