1. 程式人生 > >OC:繼承和多型碰到的坑

OC:繼承和多型碰到的坑

今天(2018.12.5)算是正式開始學OC了,加油!

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

@interface A : NSObject
- (void) whoAreYou;
@end

@implementation A

- (void) whoAreYou {
    printf("AAA\n");
}
@end

@interface B : A
- (void) sayHello;
@end

@implementation B

- (void) whoAreYou {
    printf("BBB\n");
}

- (void) sayHello {
    printf("Hello\n");
}
@end

int main(int argc, char * argv[]) {
    A *a, *b; // 編譯器希望a和b都指向A型別的記憶體空間
    a = [[A alloc] init];
    b = [[B alloc] init]; // 然而我讓b指向B型別的型別空間,好在B是A的子類,所以共享了部分記憶體,不會報錯
    [a whoAreYou];
    [b whoAreYou]; // 呼叫的是B過載的whoAreYou函式
    [(B *)b sayHello]; // 此時b的型別是A*,但是他想呼叫A這片記憶體之外的的函式(即sayHello),則應該強制型別轉換成B*型別,倘若他就想呼叫父類的方法,就沒必要強轉。
//    [(B *)a sayHello]; // 這句話會報錯,父類的型別不能強轉成子類的型別,但是子類的型別可以強轉成父類的型別
}

如果b就想呼叫父類的方法,就沒必要強轉,因為b目前的型別是A *,是可以指向父類的記憶體的,因此不會報錯,程式碼如下,則B就不用重寫函數了,程式碼如下:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

@interface A : NSObject
- (void) whoAreYou;
@end

@implementation A

- (void) whoAreYou {
    printf("AAA\n");
}
@end

@interface B : A
- (void) sayHello;
@end

@implementation B

//- (void) whoAreYou {
//    printf("BBB\n");
//}

- (void) sayHello {
    printf("Hello\n");
}
@end

int main(int argc, char * argv[]) {
    A *a, *b; // 編譯器希望a和b都指向A型別的記憶體空間
    a = [[A alloc] init];
    b = [[B alloc] init]; // 然而我讓b指向B型別的型別空間,好在B是A的子類,所以共享了部分記憶體,不會報錯
    [a whoAreYou];
    [b whoAreYou]; // 呼叫的是父類的函式,不必強轉
    [(B *)b sayHello]; // 此時b的型別是A*,但是他想呼叫A這片記憶體之外的的函式(即sayHello),則應該強制型別轉換成B*型別,倘若他就想呼叫父類的方法,就沒必要強轉。
//    [(B *)a sayHello]; // 這句話會報錯,父類的型別不能強轉成子類的型別,但是子類的型別可以強轉成父類的型別
}

又發現一個好玩的,來證明父類的型別不能強轉成子類的

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

@interface A : NSObject
- (void) whoAreYou;
@end

@implementation A

- (void) whoAreYou {
    printf("AAA\n");
}
@end

@interface B : A
- (void) sayHello;
@end

@implementation B

- (void) whoAreYou {
    printf("BBB\n");
}

- (void) sayHello {
    printf("Hello\n");
}
@end

int main(int argc, char * argv[]) {
    A *a, *b; // 編譯器希望a和b都指向A型別的記憶體空間
    a = [[A alloc] init];
    b = [[B alloc] init]; // 然而我讓b指向B型別的型別空間,好在B是A的子類,所以共享了部分記憶體,不會報錯
    [(B *)a whoAreYou]; // 我讓a強轉成(B*),輸出的竟然是AAA,說明強轉失敗啦,還是那句話,父類的型別不能強轉成子類的
    //[(B *)a sayHello]; // 這句話會報錯,因為不能強轉
}

引入一個id型別的看看?

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

@interface A : NSObject
- (void) whoAreYou;
@end

@implementation A

- (void) whoAreYou {
    printf("AAA\n");
}
@end

@interface B : A
- (void) sayHello;
@end

@implementation B

- (void) whoAreYou {
    printf("BBB\n");
}

- (void) sayHello {
    printf("Hello\n");
}
@end

@interface C : NSObject
- (void) printName;
@end

@implementation C

- (void) printName {
    printf("shijie");
}

@end


int main(int argc, char * argv[]) {
    A *a, *b; // 編譯器希望a和b都指向A型別的記憶體空間
    id c;
    a = [[A alloc] init];
    b = [[B alloc] init]; // 然而我讓b指向B型別的型別空間,好在B是A的子類,所以共享了部分記憶體,不會報錯
    c = [[C alloc] init];
    [c printName];
}