目录
概述
类的本质也是一个对象,是Class类的实例,简称“类对象”。
那么,Class类的本质又是什么呢?
探索
1#
官方给出的Class类型的定义是这样的:
typedef struct objc_class *Class
从这里我们可以看出,Class这个类的本质是一个名叫objc_class的结构体。
2#
我们知道,一个典型的类中包含两部分内容:成员变量、方法,不难推测出,结构体中应该也包含这两部分内容:
1. 由指向基本数据类型或其他结构体的指针构成的成员变量区
2. 由指向函数的指针所构成的方法区
尝试
OK,猜想完毕后,我们来尝试做一个拥有类的基本功能的结构体。
PS.类的基本功能:
1. 创建对象
2. 使用自定义的其他方法
当然这仅仅是最浅层次的模拟,不涉及到其他特性。
需求
创建一个Car结构体,要求实现:
1. 拥有speed属性
2. 提供一个new函数,以该结构体为模板创建新结构体
3. 新结构体不能使用new函数
4. 新结构体可以使用run函数,并在屏幕上输出“车子跑起来了”
代码
经过一段时间的探索之后,得到了如下代码,可以满足上述需求。
//
// main.m
// 类的本质探索
//
// Created by Azen.Xu on 15/3/14.
// Copyright (c) 2015年 Azen.Xu. All rights reserved.
//
/*
创建一个Car结构体,要求实现:
1. 拥有speed属性
2. 提供一个new函数,以该结构体为模板创建新结构体
3. 新结构体不能使用new函数
4. 新结构体可以使用run函数,并在屏幕上输出“车子跑起来了”
*/
#import <Foundation/Foundation.h>
// 函数声明
void run();
struct CarB new(); //此例说明,结构体未定义以前,也可以声明返回值为结构体的函数
// 定义结构体
// CarB结构体用来存放对象方法指针;
struct CarB{
int _speed;
void (*run)();
};
// Car结构体用来存放类方法指针
struct Car{
struct CarB (*new)();
}Car = {new}; //在定义结构体的同时赋初值是因为,结构体必须在定义之后才会分配内存,才能调用方法。
// 主程序入口
int main()
{
// 调用Car“类”的new方法生成两个newCar“对象”
struct CarB newCarA = Car.new();
struct CarB newCarB = Car.new();
// 设置newCar的_speed“实例变量”值为100
newCarA._speed = 100;
newCarB._speed = 20;
printf("A的速度是%d,B的速度是%d\n",newCarA._speed,newCarB._speed);
// 测试run方法
newCarA.run();
return 0;
}
// 函数实现
// new方法
struct CarB new()
{
struct CarB newCar = {0,run}; // 此处一定要记得赋初值
return newCar;
}
// run方法
void run()
{
printf("车子跑起来了\n");
}
总结
思路总结
通过这个例子,我们知道,采用结构体的方法可以实现与OC类相同的效果。
而一个OC类需要两个结构体来实现:
1. 结构体1用来存放类方法,其成员仅有“类方法”函数指针,且需要在声明结构体的同时定义好结构体变量(这样才能使类方法函数指针指向正确的函数)
2. 结构体2用来存放成员变量及对象方法
3. +new方法中,应当对生成的结构体初始化后(对象方法指针指向正确的函数)再返回
C方法总结
通过这个例子,对C语言知识进行了有效的复习:
结构体
1. 成员运算符“.”
2. 结构体的声明、实现、初始化(定义及实例)
//#1
//标准声明方式
struct 结构体名{
成员变量列表;
};
//标准实现方式
struct 结构体名 结构体变量名 = {初始化值,初始化值,...};
//#2
//声明同时实现并初始化
struct 结构体名{
成员变量列表;
}结构体变量名 = {初始化值,初始化值,...}
//#3
//匿名实现并初始化
struct{
成员变量列表;
}结构体变量名 = {初始化值,初始化值,...}
//#4
//typedef的应用
//声明
typedef struct 结构体名{
成员变量列表;
}结构体别名;
//实现
结构体别名 变量名 = {值值值,...}
3. 结构体成员值的修改
//#1箭头
结构体变量名->成员名 = 值;
//#2成员运算符
结构体变量名.成员名 = 值;
指向函数的指针
1. 定义
返回值名 (*指针名)(参数列表);
2. 指函数
指针名 = 函数名;
3. 使用
指针名();