[objective-c] 02 - 继承 复合

简介

本章教程主要讨论OC的继承语法以及类的复合编程模式。

  1. OC继承语法
  2. OC语言的动态特性
  3. OC的复合模式
  4. super关键字

1.OC继承语法

OC语法只支持单根继承,即一个类只能有一个父类。

继承关键字为:

@interface 类目 : 父类名

例如我们昨天声明的三角形类

@interface Triangle : NSObject

@end

表示Triangle类是继承自NSObject类。Triangle是NSObject的子类,NSObject是Triangle的父类。

OC语法中规定,通过继承方式,可以继承父类的所有方法和除私有权限以外的所有成员变量。

例如上一章的三角形类

@interface Triangle : NSObject

@property double a;
@property double b;
@property double c;

-(instancetype)initWithA:(double)a B:(double)b C:(double)c;
-(double)area;

@end
@implementation Triangle

- (instancetype)initWithA:(double)a B:(double)b C:(double)c
{
    self = [super init];
    if (self) {
        self.a = a;
        self.b = b;
        self.c = c;
    }
    return self;
}

-(double)area
{
    double s=(_a+_b+_c)/2;
    return sqrt(s*(s-_a)*(s-_b)*(s-_c));
}

本章我们可以通过继承的方法创建一个新的三角形类

@interface TriangleSub : Triangle

@end

@implementation TriangleSub

@end

可以看到我们新创建的TriangleSub类中没有声明任何方法也没有实现任何方法。但是通过继承语法,我们无偿获得了父类的所有方法和成员变量。

TriangleSub * subT = [[TriangleSub alloc] initWithA:10 B:11 C:12];
double s = [subT area];
NSLog(@"s = %g",s); // NSLog函数是OC中向控制台输出信息的函数

2.OC语言的动态特性

OC语言是动态类型语言,其表现为调用方法时,不会依据对象指针类型调用对象方法,而根据对象指针使用的内存类型调用响应的方法。

下面通过代码描述这个特性。

首先我们创建一个测试类TestClass

@interface TestClass : NSObject

-(void)test;

@end
@implementation TestClass

-(void)test
{
    NSLog(@"这里是TestClass类的test方法");
}
@end

我们继续创建两个类:

SubA继承自TestClass

@interface SubA : TestClass

@end
@implementation SubA

//重写父类的方法
-(void)test
{
    NSLog(@"这里是SubA类的test方法");
}
@end

SubB继承自TestClass

@interface SubB : TestClass

@end
@implementation SubB

//重写父类的方法
-(void)test
{
    NSLog(@"这里是SubB类的test方法");
}
@end

现在做如下测试

SubA * a = [[SubB alloc] init];
[a test]; // 这样调用没有编译错误,符合OC的语法规则,那会输出哪个结果。

根据我们之前讲的,OC的动态特性的表现形式

对象指针在调用方法是,不会根据对象指针类型调用响应方法,而是根据对象指针指向的内存类型调用响应的方法

由此可见,对象指针a的类型为SubA类型,但其指向的内存类型为SubB类型。所以用对象指针调用test方法时,会调用SubB的test方法。

其输出结果为:这里是SubB类的test方法。

由于OC语法动态特性的原因,在编写代码的过程中,对象指针类型只在编译时起作用。在运行过程中没有任何影响。

OC语法推出一个id关键字,表示在编译过程中不指定类型。

使用id类型编写代码对运行不会有任何影响。但在IDE环境中,便无法开启代码自动补全功能,因IDE工具并不知道该对象指针是什么类型,所以无法进行代码自动提示和补全。

3.OC的复合模式

在OC的复合模式就是把其他对象作为自身的一部分,以提升自身的功能。

比如我现在要制作一台电脑,电脑需要CPU,显示器,鼠标和键盘等。这些东西的研发都是很复杂的过程。如果现在有成型的CPU等组件,就可以直接用这些组件攒一台电脑。复合模式就是这样。

所以我们在制作电脑前要先找到这些组件。这些组件并不需要我们来制作,有专业的公司提供这些成型的组件。

在本章练习的SDK中提供了如下组件。

KeyBoard    键盘类
BigMouse    鼠标类
Monitor     显示器类
IntelCPU    CPU类

下面就用SDK中提供的各种组件来快速制作一台电脑。

首先我们进行电脑类的声明。需要使用的组件都声明成属性,作为电脑类的一部分。

@interface Computer : NSObject

@property(strong, nonatomic) KeyBoard *aKeyBoard;
@property(strong, nonatomic) BigMouse *aMouse;
@property(strong, nonatomic) Monitor  *aMonitore;
@property(strong, nonatomic) IntelCPU *aCPU;

@end

在这里我们先补充一下属性括号中的内容。

属性括号中的内容为属性控制符,分别对属性的读写权限,内存管理和线程操作做出相关规定。

  1. 读写权限由两个关键字控制,分别为:readonlyreadwrite。其中如果不写默认为readwrite。通常属性的读写权限都为可读可写。
  2. 内存管理权限由四个关键字控制,分别为:assgin,strong,weakcopy。如果不写,默认为assgin。如果属性类型为基本数据类型,那么只能用assgin。如果属性类型为对象指针,一般情况下用strong,特殊情况下用weakcopy。特殊情况在后面的内存管理章节会展开讲解。
  3. 线程操作权限由两个关键字控制,分别为:atomicnonatomic。其中如果不写默认为atomic。通常我们使用nonatomic作为线程操作,其具体内容在后续的多线程章节会展开讲解。

然后继续实现电脑类,因CPU等组件是电脑的一部分,所以我们需要重新电脑的初始化方法,在电脑初始化的的同时也初始化各种组件,为其分配内存。

@implementation Computer

- (instancetype)init
{
    self = [super init];
    if (self)
    {
        self.aKeyBoard = [[KeyBoard alloc] init];
        self.aMouse = [[BigMouse alloc] init];
        self.aMonitore = [[Monitor alloc] init];
        self.aCPU = [[IntelCPU alloc] init];
    }
    return self;
}

@end

经过声明组件属性,为组件的对象指针分配内存。我们就使用成型的组件快速的制作好了一个功能完整的电脑。

4.super关键字

通常继承和复合会一同使用,来快速构造一个复杂的对象。

例如现在有一个需求,要求我们快速制作一个可以除甲醛的高级空调。通常我们并不是从零开始研发,而是基于一定基础开始制作。

在这里,我提供了两个对象作为研发的基础

  1. Kongtiao类,具有制冷方法
  2. ChuJiaquan类,具有除甲醛的方法

以下是Kongtiao类的声明

@interface Kongtiao : NSObject

-(void)zhiling;

@end

以下是ChuJiaquan类的声明

@interface ChuJiaQuan : NSObject

-(void)chuJQ;

@end

首先明确我们制作的是一个空调,所有我们创建一个高级空调类继承自空调类。

然后高级空调需要有除甲醛的功能,我们通过复合模式,把除甲醛的模块作为高级的空调的一部分。

最后我们重写父类的制冷方法,在制冷过程中添加除甲醛的步骤。但是在重写的方法会覆盖掉父类原有的方法。这里我们需要在重写方法中手动调用父类原始方法。就需要用到super关键字。

@interface NewKongtiao : Kongtiao

@property(strong, nonatomic) ChuJiaQuan * cJQ;

@end
@implementation NewKongtiao

- (instancetype)init
{
    self = [super init];
    if (self)
    {
        self.cJQ = [[ChuJiaQuan alloc] init];
    }
    return self;
}
-(void)zhileng
{
    [super zhileng];
    [self.cJQ chuJQ];
}

@end

这样我们在使用高级空调制冷的同时,也同时能够除甲醛了。

时间: 2024-11-07 14:07:14

[objective-c] 02 - 继承 复合的相关文章

objective C中继承、协议、分类和多态的实现

第一.objective C中继承的实现 在oc中只有实例变量会有权限控制,实例方法和类方法是没有权限控制的,这点与c++不同,OC默认的是protected,并且在声明权限控制时,没有分号 在OC中可以像C++一样用指针运算法来访问实例变量 Rectangle.h 文件代码: #import <Foundation/Foundation.h> @interface Rectangle : NSObject { int _width; int _height; } @property (non

面向对象02 继承

继承 :解决代码的重复 #继承语法 class 子类名(父类名):pass class A: pass class B(A): pass # A 父类 基类 超类 # B子类 派生类 子类可以使用父类中的 : 方法和静态变量 class Animal: def __init__(self,name): self.name = name def eat(self): print('%s is eating'%self.name) def drink(self): print('%s is drin

011.maven 继承与聚合

聚合:对于聚合模块来说,它知道有哪些被聚合的模块,而对于被聚合的模块来说,它们不知道被谁聚合了,也不知道它的存在: 继承:对于继承关系的父POM来说,它不知道自己被哪些子模块继承了,对于子POM来说,它必须知道自己的父POM是谁: 在一些最佳实践中我们会发现:一个POM既是聚合POM,又是父POM,这么做主要是为了方便. 链接:https://www.cnblogs.com/sxpy-lj/p/7251418.html 一.继承 为了避免重复.通过继承拥有Parent项目中的配置. https:

《Effective C++》读书笔记汇总

我之前边读<Effective C++>边写下每个条款的读书笔记,这一版是C++11之前的版本.这里我将每个条款令我印象深刻的点小结一下. 1.C++包括:Plain C(面向过程).OOP(面向对象).模板(泛型和模板元编程).STL(C++标准库). 2.用inline.enum.const代替#define.#define定义的宏,一旦复杂起来,高手都很难掌控.不要带入C的习惯. 3.灵活使用const前缀.不需要进行改变的数据加上const前缀.指针的const前缀有两种形式,cons

《那些年,我们一起疯狂的C#》

v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} 那些年,我们一起疯狂的C#语言------总结 望大家认真看看哦,有惊喜哦 第一章                   第一个C#程序 大概在2000年,微软推出了一种革命性的产品--.NET 目标:任何人,在任何地

我们为之奋斗过的C#-----C#的一个简单理解

我们首先来简单叙述一下什么是.NET,以及C#的一个简单理解和他们俩的一个区别. 1 .NET概述 .NET是Microsoft.NET的简称,是基于Windows平台的一种技术.它包含了能在.NET Framework平台运行的所有编程语言. 2 C#概述 他是专门为.NET平台设计的一种语言. 3 .NET与C#的区别 .NET是一种平台,这种平台可以编译多种语言例如:VB,J#,而C#只是一种语言. 4 IDE IDE全称(Itergrated Developer Environment)

OOP⑷

1.对象数组: /** *学生类 */ public class Student { // 创建一个对象数组保存3名学生的信息 Student[] stus = new Student[3]; int age; // 年龄 String name; // 姓名 /** * 无参构造 */ public Student() { } /** * 带参构造 */ public Student(int age, String name) { this.age = age; this.name = nam

Java学习之面向对象二

###01继承的概述 *A:继承的概念 *a:继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系 *b:在Java中,类的继承是指在一个现有类的基础上去构建一个新的类, 构建出来的新类被称作子类,现有类被称作父类 *B:继承关系的子类特点 *a:子类会自动拥有父类所有非private修饰的属性和方法 ###02继承的定义格式和使用 *A:继承的格式 class 子类 extends 父类 {} *B:雇员(Employee)与研发部员工(Developer)案例: *cn

面向对象04异常

public class ExceptionTest { /** * 生活中的异常:--->摔跤 * 下楼梯的时候,我也不想摔跤,但是确实摔了! * 然后呢??难道后半辈子就不过了?? * 之后的生活肯定还得继续!!! * * 程序中的异常 : 在程序运行期间,发生了不正常的事件(代码的问题),中断了程序执行! * 从出现异常的地方,之后的代码都不会执行! * 显然不符合我们的需求! * 我们的需求--->继续执行后续的代码! * 怎么执行后续的代码? * 使用异常处理机制: * 给程序提供了