C语言的面向对象

一曲冷凌霜 提交于 2021-02-08 05:30:05

面向对象的思想,不应受某种语言的限制,面向过程的C语言同样如此。C里面没有类,可以用结构体;没有类的方法,可以使用函数指针;

最重要的,没有继承的概念,怎么解决呢?

想想强制类型转换,为什么能转换成功呢?这就为实现继承做了基础,加上前面有几篇写过可执行文件的结构,将在后面给出一种方式。

1.一个简单的类

#include<stdio.h>
#include<stdlib.h>

typedef struct Man {

	int age;
	void (*sayHi)();
}Man;

void manSayHi(){
	printf("hi ... \n");
}

Man* createMan(){
	return (Man*)malloc(sizeof(Man));
}

void deleteMan(Man* m){
	free(m);
}

Man* initMan(Man* m,int age){

	m->age = age;
	m->sayHi = manSayHi;
	return m;
}

int main(){

	int a;
	Man* m = initMan(createMan(),30);
	m->sayHi();
	printf("man age = %d \n",m->age);
	deleteMan(m);

        //这里只是让弹出的命令窗口,等待一个数值,不消失。
	scanf_s("%d",&a);
}


在结构体Man中,age相当于一个成员变量,sayHi是一个函数指针,相当于一个成员方法。

有一点需要说明,在createMan函数中,malloc函数返回的是一个void* 的指针,在这里强制类型转换成了一个 Man* 的指针,这是在VS2012 中。

在Mac下Xcode中不需要强转。

C语言中,void* 本身可以指向任意类型的指针,VS的语法检查是否过于严格了呢。


对一个类来讲,有构造 和 析构 两部,我们这里对应的构造是分成了两步:

①分配内存 createMan

②初始化 initMan

析构只有一步:

释放内存deleteMan

运行结果:


2.类的继承

提到类的继承,想想父类与子类的关系,子类可以向父类转型,这一点跟强制类型转换是否很相似?

那么只要在链接成的可执行文件中,将子类与父类的内容按顺序排放,就实现了一个继承的关系。

#include<stdio.h>
#include<stdlib.h>

#define Obj_Field void (*onDestroy)();

#define createObj(Type) malloc(sizeof(Type))

#define deleteObj(Type)\
{\
	Type->onDestroy();\
	free(Type);\
}

typedef struct Object{
	Obj_Field
}Object;


Object* initObj(void* obj){
	printf("obj init ... \n");
}
 

typedef struct Man {

	Obj_Field
	int age;
	void (*sayHi)();
}Man;

void manSayHi(){
	printf("hi ... \n");
}

void manOnDestroy(){
	printf("man on destroy ... \n");
}

Man* initMan(Man* m,int age){

	m->age = age;
	m->sayHi = manSayHi;
	m->onDestroy = manOnDestroy;

	printf("man init ... \n");

	return m;
}

int main(){

	int a;
	Man* m = initMan((Man*)createObj(Man),30);
	m->sayHi();
	printf("man age = %d \n",m->age);
	deleteObj(m);


	scanf_s("%d",&a);
}

先看运行结果:

在这里只要把 Obj_Field 这个宏放在 Man的最开始的位置上,就可以实现 继承的关系了,即使向 Object转型,也不会因截断而出错。

这是声明Obj_Field 这个宏的原因。

创建对象也用了一个宏,是为什么呢?

因为一个子类所占用的空间往往比父类的要大,所以要动态的为子类非配空间,具体的类型还未确定。

需要等到真正执行程序的时候才去决定。

那么销毁对象的方式也就与此想通了。

这里依然如此,malloc分配返回的void* 要强转成具体类型。(Windows VS2012下,Mac Xcode不需要)

Man* m = initMan((Man*)createObj(Man),30);


这样,一个简单的继承就实现了。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!