C语言:构造对象

        对象是 C 语言中最重要的概念。有基础的小伙伴可能会反问:“C 语言不是面向过程的吗?怎么会有对象呢?好像C++、Java之类的语言才有对象!”说的没错,但是这样问显然是未曾对 C 的灵魂——指针进行过探索。

        你可能听过“指针是 C 语言的灵魂所在”、“利用指针可以实现高级语言提供的操作”之类的话。

那么接下就让我们乘坐“指针”的快车,在 C 语言中构造一个真正的对象。


      既然是构造对象,那就免不了描述对象的内部结构,即对象本身的数据结构,很显然,struct 结构体就很适合,但是 struct 的短板在于无法直接存储函数。而这一点我们可以使用指针来解决。

        下面我们尝试构造一个 Student 学生的对象,定义一个对象的前提是要有对应的类是对对象的抽象

        那么,请问在开发过程中,是现有对象还是现有类呢?

        从教科书中来,那自然是现有类,再有对象。

        但在实际的项目开发中,一般应该是先有对象,然后再有类。原因就在于那句“类是对对象的抽象。”

        除非这个对象是别人已经抽象好了的,那你当然不用再额外搞一个对象了,因为已经有一个与这个对象相对应的类了......

一、对象/类的结构

        学生的一般包含姓名、年级、年纪等很多信息,为方便起见,这里只使用这三个基本信息做演示。

        为简便使用 Student 类型,在此将该结构体指针直接声明为 Student 类型

typedef struct struct_Student * Student;

struct struct_Student {
 char * name; // 姓名
 int year;    // 入学年
 int age;     // 年纪
};

二、针对属性的操作

        一般情况下,对象是动态分配空间的,对象本身不属于函数来管辖,由用户手动控制对象本身所占内存空间的释放与分配。


在 C 语言中,一般使用下表中的函数进行内存空间的操作

void *malloc(size_t size)

分配 size 字节的内存,并返回该内存的指针,若失 败返回 NULL。

void *calloc(size_t nitems, size_t size)

以 size 字节为单位,分配 ntimes 个连续的内存,并置零,并返回该内存的指针,若失败返回 NULL。

void *realloc(void *ptr, size_t size)

该内存是通过 malloc、calloc、realloc 进行分配的。若 ptr 指向 NULL,则分配新内存,并返回指向新的内存的指针,若失败返回 NULL。

void free(void *ptr)

释放 ptr 指向的内存。该内存是通过 malloc、calloc、realloc 进行分配的。


2.1 分配对象空间

        分配空间时,对 malloc 的返回值进行断言,如果返回值为 NULL,说明空间分配失败,则中断程序执行。

Student Student_new () {
 Student self = (Student) malloc (sizeof (struct struct_Student));
 assert (self != NULL);
 self->name = NULL;
 self-> age = 0;
 self->year = 0;
 return self;
}

2.2 释放对象空间

        释放空间之前,对目标对象进行判断,如果已经为 NULL,则不需要再释放。

void Student_del (Student self) {
 if (self != NULL)
  free (self);
}

2.3 其他一般方法

        一般方法如:introduce 介绍方法 对象使用之前,应当进行判断是否为 NULL,如果为 NULL,则中断程序执行。

        加上类名作为前缀是为了防止出现重名函数。

void Student_introduce (Student self) {
 assert (self != NULL);
 printf("My name is %s. I'm %d years old.\n", self->name, self->age);
}

三、类的继承

        针对 Student 类,可以通过 Person 类来继承一些属性。一般情况,仅允许单继承,如果要实现多继承,则需要使用动态数组或列表来实现。

        以下为 Person 类的实现:

typedef struct struct_Person * Person;

struct struct_Person {
 char * name;
 int age;
};

3.1 实现 Person 对象的构造

Person Person_new () {
 Person self = (Person) malloc (sizeof (struct struct_Person));
 assert (self != NULL);
 self->name = NULL;
 self-> age = 0;
 return self;
}

3.2 通过继承设计 Student 对象

        在通过继承设计 Student 对象时,Person parent 必须放置在最前面,只有这样,才能够为“多态”的实现提供便利。另外,如此安排也符合类之间继承的合理性、顺序性。

typedef struct struct_Student * Student;

struct struct_Student {
 Person parent;  // 父类
 int year;       // 独有的属性
};

3.3 实现 Student 对象的构造

Student Student_new () {
 Student self = (Student) malloc (sizeof (struct struct_Student));
 assert (self != NULL);
 self->parent = Person_new ();
 return self;
}

        通过这种实现方式,我们发现基本上无法实现函数的重写和重载。因为在 C 语言中,不允许出现重名函数。

        别忘了,我们还有指针。我们可以利用指针来为函数的调用进行“重定向”。

        仍然以 Person 和 Student 为例。

四、基于指针的函数重载与重写

struct struct_Person {
 char * name;
 int age;

 void (* introduce) (Person self)
};

// 为了给类的introduce变量赋值,该函数必须写在构造之前
void Person_introduce (Person self) {
 assert (self != NULL);
 printf("My name is %s. I'm %d years old.\n", self->name, self->age);
}

Person Person_new () {
    Person self = (Person) malloc (sizeof (struct struct_Person));
 assert (self != NULL);
 self->name = NULL;
 self-> age = 0;
 self->introduce = Person_introduce;
 return self;
}

        利用指针实现函数的重载

typedef struct struct_Student * Student;

struct struct_Student {
 Person parent;  // 父类
 int year;       // 独有的属性
};

void Student_introduce (Student self) {
 assert (self != NULL);
 printf("My name is %s. I'm %d years old.\nI am a student in the Class of %d\n", self->parent->name, self->parent->age, self->year);
}

Student Student_new () {
 Student self = (Student) malloc (sizeof (struct struct_Student));
 assert (self != NULL);
 self->parent = Person_new ();
 self->parent->introduce = Student_introduce;
 return self;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值