④--OC面向对象

    面向对象的引入——在我们熟悉的现实世界中,一切事物都是对象。对象可以是有形的,比如房屋、汽车、飞机、动物、植物;也可以是无形的,比如一项计划。对象可以是一个简单的个体,比如一个人;也可以由诸多其他对象组合而成,比如一个公司有多个部门,每个部门又由许多人组成。对类似的对象进行抽象,找出其共同属性,便构成一种类型。这些都是我们在现实世界中所熟悉的概念和方法。

编写程序的目的是描述和解决现实世界中的问题,第一步就是要将现实世界中的对象和类如实地反映在程序中。作为一种面向对象的程序设计语言,OC支持这种抽象。将抽象后的数据和函数封装在一起,便构成了 OC的“类”。

1.采用面向对象的编程方法时,要注意区分类和对象的概念:

    在面向过程的结构化程序设计中,程序的模块是由函数构成的,函数将逻辑上相关的语句与数据封装,用于完成特定的功能。在面向对象程序设计中,程序模块是由类构成的。类是对逻辑上相关的函数与数据的封装,它是对问题的抽象描述。因此,后者的集成程度更高,也就更适合用于大型复杂程序的开发。 

不妨从另一个更简单的角度来理解类。首先回顾一下基本数据类型,比如 int,double,bool 等。当声明一个基本类型的变量时,究竟声明了什么呢,看下面的语句: 

int i; BOOL b;

  显然这声明了变量 i 是用于存储 int 型数据的,变量 b 是用来存放 bool 型数据的。但是变量声明的意义不只是这个,另一个同样重要的意义常被我们忽略了,这就是限定对变量的操作。例如对 i 可以进行算术运算、比较运算等,对 b 45可以进行逻辑运算、比较运算。这说明每一种数据类型都包括了数据本身的属性以及对数据的操作。 无论哪一种程序语言,其基本数据类型都是有限的,简单地C的基本数据类型也远不能满足描述现实世界中各种对象的需要。于是 OC的语法提供了对自定义类型的支持,这就是类。

类实际上相当于一种用户自定义的类型,原则上我们可以自定义无限多种新类型。因此不仅可以用 int 类型的变量表示整数,也可以用自定义类的变量表示“时钟”、 “汽车”、“几何图形”或者“人”等对象。正如基本数据类型隐含包括了数据和操作,在定义一个类时也要说明数据和操作。 当定义了一个类之后,便可以定义该类的变量,这个变量就称为类的对象或实例,这个定义的过程也称为类的实例化。

总的来说,类相当于是模板,而对象是成品。

2.如何设计一个类,并根据类来创建对象呢?(如何用OC语言以代码的形式表现出来)

一般来说,类的设计包括这几个部分

1>类名

*类名的第一个字母必须是大写

*不能有下划线

*多个英文单词,用驼峰标识

2>属性

3>行为(功能)


代码包括两大部分类的声明和类的定义(实现

类的定义使用的关键字是@iterface和@end组合;类的实现使用的是@implementation和@end关键字组合

下面是根据一个定义一个Car类

声明:

@interface Car : NSObject
{ // 声明对象属性
    int wheels; // 轮胎个数
    int speed; // 时速(xxxkm/h)
}
@end

实现:

// 2.类的实现
@implementation Car

@end

这样就创建了一个有两个属性、没有方法的汽车类Car,

在OC语言中可使用new来实例化一个类的对象(new 实际上是从OC的根类NSObject类中继承而来的方法):

int main()
{
    // 在OC中,想执行一些行为,就写上一个中括号[行为执行者 行为名称]
    // 利用类来创建对象
    // 执行了Car这个类的new行为来创建对象
    [Car new];    
    return 0;
}

实际上new方法会返回一个指向创建的对象的指针,我们可以用一个Car类型的指针来接受返回的对象,并且修改这个被实例化的对象的wheels属性值,代码如下:

int main()
{
    // 在OC中,想执行一些行为,就写上一个中括号[行为执行者 行为名称]
    // 利用类来创建对象
    // 执行了Car这个类的new行为来创建对象
    
    // 在OC中创建对象返回的是该类型的指针
    // [Car new]会创建一个新对象,并且会返回新对象本身(新对象)
    Car *p = [Car new];
    p->wheels = 4;    
    return 0;
}
此时会发现,编译器报错,原因是属性的默认访问权限是私有的,要想修改属性的值,必须使用@public关键字类声明,于是修改类的声明部分:


@interface Car : NSObject
{ // 声明对象属性
    @public
    int wheels; // 轮胎个数
    int speed; // 时速(xxxkm/h)
}
@end
这样main函数中的代码就能顺利执行了。


3.为类添加行为和注意点

  添加行为首先要在类的声明部分添加方法声明,

#import <Foundation/Foundation.h>
@interface Car : NSObject
{ // 声明对象属性
    @public
    int wheels; // 轮胎个数
    int speed; // 时速(xxxkm/h)
}
// 方法(行为):方法名、参数、返回值(声明、实现)
// 对象的方法必须以减号-开头
// OC方法中任何数据类型都必须用小括号()括住
// OC方法中的小括号():括住数据类型
-(void) run;
@end

上面的代码是在类的声明中添加了一个跑得方法,方法名为run,添加了方法以后还要再类的实现部分添加方法的实现代码:

@implementation Car
// 方法的实现(说清楚方法里面有什么代码)
-(void)run
{
    NSLog(@"车子跑起来了");
}
@end

要让类的对象调用该方法,可以在main函数中添加如下的代码:

[p run];

4.方法与成员变量的调用注意点

每个被实例化的对象都占据自己独立的内存,包括它的成员变量的内容,当一个类的实例(也就是对象),调用方法中有对属性值的引用,则是使用他自己的属性值,而与其他类的属性无关。看下面的代码:

/*
 人
 类名:Person
 属性(成员变量、实例变量):体重、年龄
 行为(方法):走路、
 */
/*
 1.类的声明
    *成员变量
    *方法的声明
 */
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
    // 成员变量
    @public
    int age;
    double weight;
}
//方法声明
-(void)walk;//没有参数就不用小括号
-(void)eat;
@end

//2类的实现
@implementation Person
-(void)walk
{
    NSLog(@"%d岁的人走了一段路", age);
}
-(void)eat
{
    NSLog(@"体重%f的人吃东西", weight);
}

@end
int main()
{
    Person *p = [Person new];
    p->age = 20;
    p->weight = 50.0;
    [p walk];
    
    Person *p2 = [Person new];
    p2->weight = 60.0;
    [p2 eat];
    return 0;
}


执行的结果是:


2014-12-18 15:11:21.449 a.out[4870:507] 20岁的人走了一段路
2014-12-18 15:11:21.451 a.out[4870:507] 体重60.000000的人吃东西

5.OC对象跟函数参数

OC对象被当做函数的参数经常会一起一些意想不到的问题,但只要认清一点就可以很好地把我,避免出错:

OC对象是指向内存中实例化的对象的指针。看下面的例子:

// 类的声明和实现部分
@interface Car : NSObject
{
    @public
    int wheels;
    int speed;
}
-(void)run;
@end

@implementation Car
-(void)run
{
    NSLog(@"%d个轮子,速度为%dkm/h的车子跑起来", wheels, speed);
}
@end

void test1(Car *newC)
{
    newC->wheels = 5;//同一指向的指针修改值,最终改变了c
}


int main()
{
    Car *c = [Car new];
    c->wheels = 4;
    c->speed = 250;

    test1(c);
    [c run];
    return 0;
}

首先内存中实例化了一个Car类型 并由变量c指向了它,语句test1(c)执行之后,形参newC有了与c相同的值,

函数的内部语句newC->wheels = 5;执行后将newC指向的那个对象的wheels改为了5,这同时也是c指向的对象,于是在执行[c run];语句时,自然会输出:

5个轮子,速度为250km/h的车子跑起来

在看下面的例子:

void test2(Car *newC)//指针赋值是将指向的地址赋值*********其实就是改变指向
{
    Car *c2 = [Car new];
    c2->wheels = 5;
    c2->speed = 300;
    
    newC = c2; //改变了newC的指向
    newC->wheels = 6;//不同指向的指针修改值,最终没有改变c
}

int main()
{
    Car *c = [Car new];
    c->wheels = 4;
    c->speed = 250;
    
    //test(c->wheels, c->speed);
    //test1(c);
    test2(c);
    [c run];
    return 0;
}

在这个例子中,自始至终没有和c相同指向的指针去修改它所指向的实例对象,所以输出结果为:

4个轮子,速度为250km/h的车子跑起来

6.OC方法跟函数的区别

方法

 1.对象方法都是以减号-开始

 2.对象方法的声明必须写在@interface@end之间

    对象方法的实现必须写在@implementation@end之间

 3.对象方法只能由对象来调用,

 4.对象方法归类、对象所有 

 

 函数

 1.函数能写在文件中的任意位置(@interface@end之间除外),函数归文件所有

 2.函数调用不依赖于对象

 3.函数内部不能调用对象的成员变量


7.方法声明和实现(类方法和对象方法,带参数的方法)

当OC方法中带参数时,OC方法中一个参数对应一个冒号,函数名通常中通常语义中包含第一个参数名的描述,如

-(int)sumWithNum1:(int)num1;  // 带一个参数的方法

当有多个参数是从第二个参数起,以空格开始依次添加参数描述信息、冒号、参数类型、参数名,如

-(int)sumWithNum1:(int)num1 andNum2:(int)num2; // 官方建议这样写

每个方法中有几个参数,方法名中就有几个冒号,如


-(int)pingFang:(int)num;

方法名为:pingFang:

也就意味着所有的描述信息加冒号组成了方法名 -( int )sumWithNum1:( int )num1 andNum2:( int )num2; 

方法名为:sumWithNum1: andNum2:

8.匿名对象

有时候利用OC创建一个对象后并没有用该对象类型的指针指向它,而是直接调用了方法或者做了其他事情,这样的对象就叫做匿名对象(没有指向它的变量名)。如

#import <Foundation/Foundation.h>
@interface Car : NSObject
{
    @public
    int speed;
}
-(void)run;
@end

@implementation Car
-(void)run
{
    NSLog(@"速度为%d的车跑起来", speed);
}
@end


int main()
{
//    Car *c = [Car new];
//    
//    c->speed = 250;
//    [c run];
    
    [Car new]->speed = 300;
    [[Car new] run];//造成内存泄露
    return 0;
}


上面的代码中创建了两个不同的匿名对象,因而当第二个匿名对象执行run方法的时候,其值与第一个对象无关,程序执行的结果为:

速度为0的车跑起来


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值