硬核,用C语言实现面向对象!!!

用C语言实现面向对象,听起来就有不可思议的感觉,那真的可以实现吗?我觉得OK!

要使用C语言这种面向过程的语言来实现面向对象,首先要做的事情是去了解面向对象是怎样的概念,例如:继承的本质是怎样的一回事,多态又是怎么来的。
在面向对象语言中,继承通过子类声明为某个父类的继承,在C++中,继承的方式有public 继承,private 继承,protected 继承,分别为公有继承,私有继承,保护继承,但是值得注意的是,在往后的高级语言中,比如说Java语言,C#语言,都仅提供公有继承,为什么呢?因为私有继承和保护继承带来的复杂性远大于实用性。

特立独行的多态又是何方神圣?(独白 : 多态多态,一种代码,多种状态)要掌握多态,首先得知道,编译原理里难以理解的的静态连编,动态连编。
简单来说,静态连编就是编译器在编译期间就可以确定该调用的对象是什么,而动态连编刚好相反。

C++如何实现多态?通过virtual关键字定义虚函数,而虚函数又有纯虚函数!在这,纯虚函数的内容就一笔带过,略微提及了,纯虚函数用于实现抽象类。


class Parent
{
protected:
	 int mi;
	 int mj;
public:
	virtual void print()
 	{
  		cout << " mi = " << mi 
  		     << " mj = " << mj << endl;
 	}
};

class Child : public Parent
{
private:
 	int mk;
public:
 	Child(int x,int y,int z)
	 {
  		 mi = x;
 		 mj = y;
 	 	 mk = z;
 }
	virtual void print()
	 {
	  cout << " mi = " << mi 
  	       << " mj = " << mj 
  	       << " mk = " << mk << endl;
	 }
};

如果要在子类中重写父类中的成员函数,则必须使用虚函数声明,否则重写是没有意义的。子类中如果重写了父类中的同名函数,会发生同名覆盖,在子类中直接访问的就是子类的成员函数,(如果想调用父类的同名函数,解决办法是利用作用域分辨符来调用父类的成员函数)。
学习是循序渐进的,掌握了虚函数,多态的真正意义就开始浮现了。

void print_your_name(Parent* p)
{
	 p->print();
}

Parent p;
Child c;
print_your_name(&p);
print_your_name(&c);

阅读至此,我想应该来个little episode,赋值兼容,不得不说,C++的强大是天生!子类对象可以用来初始化父类对象,子类对象可以赋值给父类对象,父类对象指针又可指向子类对象,父类引用又可代替子类对象,所以上图所写的函数参数其实可以输入子类对象,因为什么?赋值兼容。赋值兼容,赋值兼容。为什么要强调三次,因为在设计模式里,这样的写法是随处存在。题外话了,继承和多态都是设计模式里的中流砥柱,至关重要。

纸上谈兵,毫无益处。现在就用C语言实现面向对象,启航吧!

//code.h

#ifndef _CODE_H_
#define _CODE_H_
typedef void Class;       // 作为中间值,既可输出变量地址,又可接收参数地址
typedef void Derived;      // 作为子类
 
Class* Class_Demo_Create(int i,int j);
int Class_Demo_getI(Class* pthis);   // 手工传递地址
int Class_Demo_getJ(Class* pthis);
int Class_Demo_Add(Class* pthis,int value);
void Class_Demo_Free(Class* pthis);
 
Derived* Derived_Demo_Create(int i,int j,int k);
int Derived_Demo_getK(Derived* pthis);
int Derived_Demo_Add(Derived* pthis,int value);

#endif

待我自圆其说吧,为什么要把Class定义为void的呢,因为C语言里没有private关键字,那如何实现呢,同样的,要知其然,必先知其所以然。声明为私有的属性即成员变量,不能被外界直接访问,只能通过成员函数访问,当我们使用void接收参数时,可以为任意的指针类型,当我们使用void作为返回值,也可以返回任意类型的指针。But 要使用所创建的对象,必须要进行强制类型转换。

实现继承和多态,有两个关键点是,继承其实在内存中是直接复制了父类的成员变量,多态使用的虚函数生成的时候编译器自动给每个对象添加虚函数表,顾名思义,就是用来存放虚函数的表,在C++中,这是一种数据结构,我们用结构体来代替就可以了,通过虚函数表找到对象要调用的真正函数。

// code.c

#include <malloc.h>
#include "code.h"

static int Virtual_Class_Demo_Add(Class* pthis,int value);
static int Virtual_Derived_Demo_Add(Derived* pthis,int value);

struct Vtble      // 虚函数表
{
	 int (*padd)(Derived*,int); // 函数指针
};

struct Class_Demo
{
	 struct Vtble* mtble;  // 指向虚函数表的指针
	 int mi;
	 int mj;
};

struct Derived_Demo
{
	 struct Class_Demo d;  // 模拟继承于父类
	 int mk;
};

static struct Vtble Class_Demo_vtble =    // 父类的虚函数表
{
 	Virtual_Class_Demo_Add  
};

static struct Vtble Derived_Demo_vtble =  // 子类的虚函数表 
{ 
	 Virtual_Derived_Demo_Add
};

Class* Class_Demo_Create(int i,int j) // 返回void*类型,模拟私有成员,使之不能在外界直接访问
{
 struct Class_Demo* ret = (structClass_Demo*)malloc(sizeof(struct Class_Demo));

	if (NULL != ret)
 	{
 		 ret->mtble = &Class_Demo_vtble;   // 关联虚函数表
 		 ret->mi = i;
 		 ret->mj = j;
	 }
	return ret;
}

int Class_Demo_getI(Class* pthis)
{
	 struct Class_Demo* obj = (struct Class_Demo*)pthis;  // 模拟成员函数,调用私有成员
	 return obj->mi;
}

int Class_Demo_getJ(Class* pthis)
{
	 struct Class_Demo* obj = (struct Class_Demo*)pthis;
 	 return obj->mj;
}

int Class_Demo_Add(Class* pthis,int value)
{
	 struct Class_Demo* obj = (struct Class_Demo*)pthis;
	 return obj->mtble->padd(pthis,value);     // 实现多态,关键所在
}

static int Virtual_Class_Demo_Add(Class* pthis,int value) // 真正的实现函数
{
	 struct Class_Demo* obj = (struct Class_Demo*)pthis;
	 return obj->mi + obj->mj + value;
}

Derived* Derived_Demo_Create(int i,int j,int k)
{
	struct Derived_Demo* ret = (struct Derived_Demo*)malloc(sizeof(struct Derived_Demo));
	if (NULL != ret)
	 {
	 	 ret->d.mtble = &Derived_Demo_vtble;
 		 ret->d.mi = i;                   // 模拟继承父类中的变量
 	 	 ret->d.mj = j;
 		 ret->mk = k;
 	 }
	return ret;
}

int Derived_Demo_getK(Derived* pthis)
{
 	struct Derived_Demo* obj = (struct Derived_Demo*)pthis;	
	return obj->mk;
}

static int Virtual_Derived_Demo_Add(Derived* pthis,int value)
{
	 struct Derived_Demo* ret = (struct Derived_Demo*)(pthis);
 	 return ret->mk + value; 
}

int Derived_Demo_Add(Derived* pthis,int value)
{
 	struct Derived_Demo* ret = (struct Derived_Demo*)(pthis);
	return ret->d.mtble->padd(pthis,value); 
}

void Class_Demo_Free(Class* pthis)
{
	 free(pthis);     // 释放地址,可以为任意类型,亦可用来释放子类对象
}

大神Linus说,talk is cheap,show your code.代码如上,但是单单看代码,神仙也会被绕晕 。 所以要实现用C语言写面向对象,必须深入理解c++中的面向对象的实现原理,这时肯定有异声传来,那为什么不是其他高级语言呢?因为其他高级语言是以c++为基础的,掌握c++ 中的面向对象领悟了,把整个过程理解清楚,使用什么语言,都可以实现面向对象。


// main.c

#include <stdio.h>
#include "code.h"

void run(Class* pthis,int v) // 展现多态的函数
{
	 int r = Class_Demo_Add(pthis,v);
	 printf("result = %d\n",r);
}

int main(int argc, char const *argv[])
{
	 Class* c = Class_Demo_Create(1,1);
	 Derived* d = Derived_Demo_Create(2,2,2);
	 printf("mk = %d\n",Derived_Demo_getK(d));
 	 printf("Class_Demo_Add = %d\n",Class_Demo_Add(c,3));
 	 printf("Derived_Demo_Add = %d\n",Derived_Demo_Add(d,3));

	 run(c,3);
	 run(d,3);
	 Class_Demo_Free(c);
	 Class_Demo_Free(d);
	
	 return 0;
}

输出结果嘛,上机试一下就知道了。

猜你喜欢

转载自blog.csdn.net/Dream136/article/details/104455137
今日推荐