如何调用父类方法

4
我需要调用我的类的父方法。
@class Grandparent
+--->@class Parent   
     +---->@class Child

每个类都实现了一个方法:
-(void)foo

如果我想从子类中调用父类方法foo,我可以使用以下代码:
[super foo]

如果我想调用祖父母的foo,我该怎么做? 这是不可能的。
[super [super foo]]

Ant ideas?


听起来像是设计上的失误。你永远不应该被迫做这样的事情。 - VdesmedT
5个回答

6
当然,你可以通过父类的帮助来实现这一点。如果你的foo调用[super foo],而你的超类又因为期望这种行为而调用[super foo],那么你就完成了。这是一个常见的模式(例如-init-dealloc)。
但是,你不能直接使用普通的Obj-C语法来跳转。每个子类在其状态和方法周围都定义了自己的类语义。如果你可以随意调用继承链中的任何实现,而中间实现对此一无所知,那么没有任何实现会对其自身状态的完整性有任何保证,并且它将打破类的抽象。
换句话说,我讨厌成为这个人,但如果这似乎是你真正想做的事情,你应该重新考虑你的设计。(如果是这样,请随时打开一个新问题来讨论你的对象模型的设计。这里的人们将很乐意协助。)
话虽如此,从技术上讲,我怀疑你可以通过直接处理Obj-C运行时来实现这一点。你可以获取你对象的类引用,然后是其超类,然后是它的超类,并从其中获取你想要的方法实现。然后用你的对象调用它。这方面的代码是读者的练习。:) 这里有文档

我是一名C++程序员,如果我想的话,我可以调用 void Child::foo() { Grandparent::foo(); } 这是一种正常的操作方式... - Chiodo
Chido,Objective-C 的主要区别在于方法调用是在运行时确定的。当您调用 [foo bar] 时,您并不是在调用 foo::bar(),而是在询问“如果您有 bar(),请执行它”,这是完全不同的事情。您可以在运行时添加和删除方法-请查看 Aspect Programming http://davedelong.com/blog/2009/04/13/aspect-oriented-programming-objective-c - Stephen Furlani
@Chiodo:是的,你可以这样做。但是,能够显式指定一个基类来调用 foo 的能力实际上是多重继承的副作用;由于可能有多个基类,因此需要能够说明你正在谈论谁的 foo。你也可以在那里指定 Grandparent,但这似乎对我来说非常脆弱,有很多原因需要避免。尽管我的设计意见不同,但你无法在 Obj-C 中做到相同的事情。这里的正常模式是通过直接父类调用。 - Ben Zotto

1

如果你觉得需要这样做,那么它可能是一个糟糕的设计。你应该重新考虑你正在做的事情,沿着quixoto的答案思考。quixoto提到了Objective-C运行时库,但NSObject有实例和类方法来完成这些工作。像quixoto一样,我会把这留给你作为练习。要查看的方法包括-(Class)class+(Class)superclass+(IMP)instanceMethodForSelector:SEL,你需要阅读关于SELIMP类型以及如何通过IMP调用方法的部分。

如果你编写的代码看起来很糟糕(它确实会这样,不用担心),那么很可能是因为你不应该这样做。


1
有那么多老师啊!我已经改变了设计……只需要修改两分钟,就没有家庭作业了。 - Chiodo

0
如果您真的想这样做(不确定为什么),您可以将 Parent 与 GrandParent 进行连接([super foo])。然后,当 Child Foo 调用 Parent Foo 时,它将调用 GrandParent Foo。
或者,您可以在父类上创建一个调用 [super foo] 的方法。

0

当你在 iPhone 上时,你会看到这样的设计模式:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

如果您创建了一个新的UIViewController子类。正如其他人建议的那样,当在子类中重载方法时,应遵循这种模式。
@implementation Grandparent
    - (void) printSelf
    {
        NSLog(@"Grandparent");
    }
 @end 

@implementation Parent
    - (void) printSelf
    {
        [super printSelf];
        NSLog(@"Parent");
    }
@end 

@implementation Child
    - (void) printSelf
    {
        [super printSelf];
        NSLog(@"Child");
    }
@end 

我认为你不能这样做,因为方法调用是在运行时确定的,而不是编译时。但是对于Java或C++来说,由于语言的绑定和分派规则,这可能会起作用。
@implementation Child
    - (void) printSelf
    {
        [(Grandparent *)self printSelf]
    }
@end

试试看,但我怀疑它会起作用。


4
这不起作用,因为类型并不影响结果。如果self确实是Child类的成员,它仍会接收到printSelf消息,并且像你怀疑的那样以相同的方式分发,也就是说指向最派生的实现。 - Ben Zotto
此外,Java 中的所有方法和 C++ 中的虚拟方法都是根据接收者的运行时类型而不是静态类型进行分派的。这与强类型和弱类型并没有太大关系,而是与语言的绑定和分派规则有关。 - Geoff Reedy
@quixoto 我没想到会这样。@Geoff,我会改变我的语言...术语从来没有适当地留在我的脑海中。 - Stephen Furlani

0

我不确定为什么你想要这样的东西,因为它会破坏面向对象设计,但听起来很有趣。这是它的可工作代码:

#import <objc/message.h>

...

- (void)foo {
    struct objc_super x = {
        self,
        [[self superclass] superclass] // or any class compatible with self; repeat for more fun :)
    };
    objc_msgSendSuper(&x, @selector(foo));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接