OC(Objective-C) 实现面向对象三大特性(封装、继承、多态)的方式,其核心在于 C语言 + Runtime(运行时机制)。
下面我们来详细拆解OC是如何实现面向对象的。
核心思想:从 C 结构体到 OC 对象
本质上,每一个 OC 对象(如 NSObject *obj)都是一个指向结构体的指针。
-
封装
-
实现方式:通过
@interface和@implementation来实现。 -
底层原理:每个 Objective-C 类在编译后,都会对应一个 C 语言的结构体(struct)。这个结构体的第一个成员通常是
Class isa,它指向类的元数据(类对象),这是运行时机制的基石。
示例:
当你定义一个类Person:// Person.h (接口声明 - 封装) @interface Person : NSObject { @private NSString *_name; // 实例变量(Ivar) } @property (nonatomic, copy) NSString *name; // 属性(自动生成getter/setter) - (void)sayHello; // 方法声明 @end底层近似结构(概念上):
struct Person_IMPL { Class isa; // 继承自NSObject,所以第一个成员是isa NSString *_name; // 封装在结构体中的实例变量 };-
@public,@protected,@private关键字用于控制实例变量的访问权限,实现了数据隐藏。 -
@property编译器会自动生成对应的getter和setter方法,这些方法就是对内部实例变量进行安全访问的接口,进一步加强了封装性。
-
实现方式:通过
-
继承
-
实现方式:通过
:父类名的语法实现。 - 底层原理:结构体的内存布局。子类对应的结构体,其内存布局的第一个部分就是父类的结构体。这就是为什么子类可以访问父类的属性和方法,因为从内存角度看,子类对象开头就是一个完整的父类对象。
示例:
@interface Student : Person @property (nonatomic, copy) NSString *school; @end底层近似结构(概念上):
struct Student_IMPL { struct Person_IMPL person_OBJ_Storage; // 本质上就是包含一个父类结构体 NSString *_school; };- 当一个
Student对象被创建时,它的内存中不仅包含_school,也包含从Person继承来的isa和_name。 - 方法调用时,如果子类没有实现,就会沿着这个继承链(通过
isa指针)去父类中查找。
-
实现方式:通过
-
多态
- 实现方式:多态在 OC 中主要通过 动态类型(Dynamic Typing) 和 动态绑定(Dynamic Binding) 来实现,这依赖于强大的 Runtime 机制。
-
底层原理:
-
动态类型:
id类型和isa指针。一个对象在运行时才知道其真实类型。isa指针指向对象的类,运行时可以通过isa查询到对象的实际类型。 - 动态绑定:消息传递(Messaging) 机制。这是 OC 多态最核心的体现。
-
动态类型:
示例:
Person *p1 = [[Person alloc] init]; Person *p2 = [[Student alloc] init]; // 多态:父类指针指向子类对象 [p1 sayHello]; // 调用 Person 的 sayHello 方法 [p2 sayHello]; // 调用 Student 的 sayHello 方法(如果Student重写了)消息传递的简化过程:
当执行[p2 sayHello]时,编译器会将其转换为一个运行时函数调用objc_msgSend(p2, @selector(sayHello))。-
objc_msgSend会首先找到p2指向的对象。 - 通过对象的
isa指针找到对应的类对象Student。 - 在
Student的方法列表(method list)中查找sayHello方法。 - 如果找到,就跳转到该方法的实现(函数指针)并执行。
- 如果没找到,就通过类对象的
super_class指针去父类Person的方法列表中查找,直到根类(NSObject)。
- 这种运行时才决定执行哪个方法实现的机制,就是动态绑定。它允许不同的对象(
Person对象和Student对象)对同一消息(sayHello)做出不同的响应,这就是多态。
总结:Runtime 是面向对象的引擎
| 面向对象特性 | OC 实现方式 | 底层支撑 |
|---|---|---|
| 封装 |
@interface / @implementation、@property、访问控制符 |
C 结构体 |
| 继承 |
: 父类名 语法 |
结构体的内存布局(子类结构体包含父类结构体) |
| 多态 |
动态类型(id, isa)和 动态绑定(消息传递) |
Runtime 运行时机制(objc_msgSend、方法列表、继承链) |
关键结论:
Objective-C 的面向对象不是由编译器静态决定的,而是由 Runtime 这个动态系统在程序运行时动态创建的。类的结构、方法的查找、消息的传递都是在运行时发生的。这使得 OC 非常灵活,支持如 方法交换(Method Swizzling)、动态添加方法/属性 等高级特性,这也是它与 C++ 等语言在实现面向对象上最根本的区别。