类和对象以及对象指针

类的定义

首先在学习类之前,我们必须知道什么是类。所谓类就是一种自定义数据类型,可以使用类来定义变量,这种类型的变量相当于指针类型的变量。也就是说,所有类都是指针类型的变量。我们也可以将类理解为具有统一特征的一群对象。

对象的定义

所谓对象,简单的理解,其实就是具体的实体。这就和类联系了起来,因为类是一种抽象的存在,所以对象就是由抽象引发出来的实体,举个例子,我们经常说人类,人类就是一种类,而我们如果说人,就是由人类引出来的实体。

定义类

组成

要想定义一个类,我们需要有两个步骤。分别是:接口部分,实现部分。
接口部分:定义该类包含的成员变量和方法。
实现部分:为该类的方法提供实现。
定义接口部分的语法,代码如下:

@interface MyClass : NSObject  //其中MyClass是类名,NSObject是父类
{
   int  _count;  
   id   _data;
   NSString*  _name;
}//成员变量声明

- (id)initWithString:(NSString*)aName;

+ (MyClass*)createMyClassWithString:(NSString*)aName;//方法声明
@end

其中@interface是用于声明定义类的接口部分,@end表明定义结束。

成员变量:用于描述该类的对象的状态数据。
方法:用于描述该类的行为。比如说我们定义类一个人,程序需要关心人具有工作行为,那么程序就应该为人这个类声明工作方法。
一般来说,我们会将定义类的接口声明部分放在头文件中。也就是说,定义类接口部分的源代码应该命名为*.h 文件。

方法声明的语法

在这里插入图片描述

方法类型标识:该标识符要么是+,要么是-,其中,+代表该方法是类方法,直接用类名即可调用。-代表该方法是实例方法,必须用对象才能调用。
方法返回值类型:返回值类型可以是OC允许的任何数据类型,包括基本类型、构造类型和各种指针类型。如果声明了方法返回值类型,则方法体内必需有一个有效的return语句,该语句返回一个变量或一个表达式,这个变量或者表达式必须与此处声明的类型匹配。除此之外,如果一个方法没有返回值,则必须使用void来声明。
方法签名关键字:OC的方法签名关键字由方法名、形象标签和冒号组成。方法名命名规则与成员变量命名规则相同,但不需要以下划线开头,通常建议方法名以英语动词开头。除第一个形参外,OC建议为后面的每个形参都指定一个“形参标签”,该形参标签可以很好的说明该形参的作用。另外一旦在定义方法时指定了形参列表,则调用该方法时必须传入对应的参数值——谁调用方法,谁负责为形参赋值。

方法

-(void)eat; //无参数无返回值
-(double)square:(double)number;//一个参数
-(void)setName:(NSString *)name andAge:(int) age;//多个参数

方法实现

-(void)eat{
	NSlog(@"very good");
}
-(double)square:(double)number{
	return number * number;
}
-(void)setName:(NSString *)name andAge:(int) age
{
	_name = name;
	_age = age;
}

对象

定义类之后,接下来就可以使用该类了,可从如下3方面来使用类。

1.定义变量。
2.创建对象。
3.调用类方法。

定义变量的语法为:
类名 * 变量名;

创建对象的语法为:
[[类名 alloc] 初始化方法];

在上面的语法格式中,alloc是OC的关键字,该关键字负责为该类分配内存空间,创建对象。除此之外,还需要调用初始化方法对该实例执行初始化。由于所有的对象都继承了NSObject类,因此所有的类都有一个默认的初始化方法:init。

比如我们定义一个FKPerson类的用法:

FKPerson * person;
person = [[FKPerson alloc] init];

OC调用方法的语法格式为:
[调用者 方法名 :参数 形象标签 :参数值 …];
如果方法声明中声明了多个形参,那么调用方法时需要为每个形参传入相应的参数值。

另外如果访问权限允许,OC允许直接通过对象来访问成员变量。格式如下:
对象->成员变量名

让我们来定义一个FKPerson类。

//先定义一个FKPerson *类型的变量
FKPerson* person;
//创建FKPerson对象,赋给person变量
person = [[FKPerson alloc] init];

上面的代码也可以简写为:

FKPerson* person = [[FKPerson alloc] init];

在OC程序中,一般只导入类的接口部分,也就是只会使用#import"FKPerson.h",不会导入类的实现部分,因此,此时需要使用如下命令来编译该程序:

clang - fobjc - arc - framework Foundation FKPerson.m FKPersonTest.m

通过类来调用类

//调用有参数的方法, 必须传入参数
[person say:@"Hello, I love iOS"];
[person setName: @"孙悟空" andAge: 500];
//调用无参数的方法,不需要传入参数
//方法有返回值,可以定义一个类型匹配的变量,来接收返回值
NSString* info = [person info];
NSLog(@"person的info信息为: %@", info);
//下面调用test的方法会引起错误,因为test方法是在实现部分定义的,应该被隐藏
//[person test];
//通过类名来调用类方法
[FKPerson foo];

对象和指针

首先我们先看一行代码:

FKPerson * person = [[FKPerson alloc] init];

这行代码创建了一个FKPerson实例,也被称为FKPerson对象,这个FKPerson对象被赋给person变量。
这行代码中实际产生了两个东西: 一个是person变量,一个是FKPerson对象。

从FKPerson类定义来看,FKPerson对象应该包含了3个成员的变量,两个可以暴露的成员变量:person setName: @“孙悟空” andAge: 500,和一个被隐藏的成员变量。而成员变量是需要内存来储存的。因此,在创建FKPerson对象时,必须头对应的内存来储存FKPerson对象的成员变量。
如图所示:
在这里插入图片描述

由此可见,其实FKPerson对象是由许都块内存组成,不同的内存块存储了不同的成员变量。当把这个FKPerson对象赋值给一个FKPerson变量时,因为FKPerson类型的变量本质就是一个指针变量,所以person变量仅仅只是存储了FKPerson对象在内存中的首地址。形象的说,可以认为FKPerson*类型的变量指向实际的对象。

从本质来说,类也是一种指针变量,因此,程序中定义的FKPerson*类型只是存放一个地址值,它该保存在该main()函数的动态存储区,它指向实际的FKPerson对象,而真正的FKPerson对象则放在堆(heap)内存中。

也就是说,在main()方法的动态存储区保存的指针变量只想保存了该对象的地址,并非该对象的成员变量数据。当我们调用person指针变量的成员变量和方法时,实际上是访问person所指向对象的成员变量和方法。简单的来说,我们调用person指针变量,先获得的是这个指针变量保存的对象的地址,通过地址我们才找到了真正的对象,然后访问对象的成员变量和方法。

FKPerson *p2 = person;

上面的代码,我们又定义了一个新的FKPerson*变量,同时将原本person中存储的地址值又赋给了p2。此时,我们无论是访问person的成员变量和方法,还是访问p2的成员变量和方法,都访问的是FKPerson对象的成员变量和方法,将会返回相同的访问结果。

总结

其实定义一个类就是为了重复的去创建该类的实例,也就是对象,因为一个类就是多个具有相同特征的实例,当我们创建了一个类,我们就可以去定义对象,比如我们定义了水果类,而苹果,西瓜,芒果都是这个类的对象,都是从抽象的概念引出的实例。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值