C语言实现C++多态思想

前言:

接触C++已经有一段时间了(工作时绝大部分时间使用的是C,因为从事的是嵌入式这方面,也用C#做Windows的软件界面),感慨颇多,尤其是在语法方面,和C比较起来更自由和复杂,但是自由并不意味着就是不严谨,我觉得C++的严谨程度胜过C。 C是C++的子集,C++完全兼容C的语法,而且,C++的思想,理论上,都可以用C语言进行实现,最近在学习Linux的内核源码和U-boot源码,里面用C实现C++面向对象的思想非常非常多,而且写的非常的精彩,我是没想到原来C语言有这么大的威力,灵活多变的用法也让我这只菜鸟甚为惊叹,彷佛打开了一个新世界O(∩_∩)O

C++多态基础:

多态的地位

多态应该是面向对象的三大思想的集大成者吧。不仅需要封装和继承来作为多态的实现条件,还可以使用未来,把未来的接口都设计好,所以说多态是面向对象三大概念最为顶级的思想,远远超过的程序的代码。多态是设计模式的基础,多态是框架的基础。

C++编写多态

  • 要有继承
  • 要有虚函数重写(子类和父类里要有同名函数,并用virtual声明)
  • 用父类指针(父类引用)指向子类对象
    先用C++编写一个最简单的多态的程序来作为后面C语言编写多态的参照
class A				//声明一个父类
{
public:
	virtual void print(int a, int b, char* p)    			//虚函数
	{
		cout << "result=" << a + b << p << endl;
	}
};
class B : public A			//子类B继承于父类A
{
public:
	virtual void print(int a, int b, char* p)			//虚函数
	{
		cout << "result=" << a * b << p << endl;
	}
};
class C :public A			//子类C继承于父类A
{
public:
	virtual void print(int a, int b, char* p)      //虚函数
	{
		cout << "result=" << a - b << p << endl;
	}
};
class D :public A			//子类D继承于父类A
{
public:
	virtual void print(int a, int b, char* p)
	{
		cout << "result=" << a / b << p << endl;		//虚函数
	}
};
void mainOP2(A* myp, int a, int b, char* p)      //框架
{
	myp->print(a, b, p);			
}
void main()
{
	A* ParentPT = NULL;  //创建一个父类指针
	A m0;
	B m1;
	C m2;
	D m3;
	mainOP2(&m0, 10, 5, "hello");
	mainOP2(&m1, 10, 5, "hello");
	mainOP2(&m2, 10, 5, "hello");
	mainOP2(&m3, 10, 5, "hello");
	system("pause");
}

B,C,D全部是A的派生类,void mainOP2(A* myp, int a, int b, char* p) 可以看作是一个程序的主框架,通过函数参数里的父类指针myp来指向A,B,C,D,用一句myp->print(a, b, p); 代码,就可以实现不同多个不同类的print(a, b, p);函数。那么同样的调用语句,有多种不同的表现形态。
main函数就是将不同的对象类型传进mainOP2函数里,mainOP2表现出不同表现形态。这应该是一个最浅显简单的多态表现形式了,应该大家都能看得懂。

C++类中的虚函数表

当在类中有virtual声明虚函数的时候,编译器会在每个类中生成一个虚函数表(偷偷的生成),只有被声明为virtual才有资格进入虚函数表。虚函数表本质是一个存储类成员函数指针的数据结构。虚函数表是由编译器自动生成与维护的。
然后,在创建一个类的实例化对象的时候,例如 A m0; 如果这个类A里边存在虚函数,那么编译器会偷偷的创建一个指向类A的虚函数表的指针,就是传说中的vptr指针,这个指针是确确实实存在的,不信可以sizeof(A)看一下是多少,因为类A里面没有任何一个成员属性,所以理论上编译器为了让对象有一个独一无二的内存空间,会给类A分配1个字节,但是实际上打印sizeof(A)是4个字节,因为编译器偷偷的创建了一个vptr指针。
void mainOP2(A* myp, int a, int b, char* p)函数在执行的时候,编译器会判断函数体里面的执行语句print(a, b, p);是不是虚函数,如果不是虚函数,编译器可直接确定被调用的成员函数,属于静态联编。
如果是虚函数,编译器根据传进来的实参的vptr指针,所指的虚函数表去查找print()函数,并调用,属于动态联编。因为不管你传进来是父类的变量还是子类的变量,都
有一个vptr指针,这样就可以根据具体对象调用具体的函数。
多态屌就屌在这里,在你创建类的实例化对象的时候,就已经提前布局了,给你偷偷多了一个vptr指针的机制。
在下面的C语言实现多态的过程中,C语言也会有相同的一种机制来映射这个虚函数表。

用C语言实现C++多态

前面的一堆铺设,终于讲到重点了,d=====( ̄▽ ̄*)b
先以单个函数为例:

typedef void(*FuncPT)(int a, int b, char* p);
void print1(int a, int b,char* p)
{
	cout << "result=" << a + b << p << endl;
	/* 理论上来说,用纯粹的C语言实现,这里应该是用printf()函数,但是主要是为了和C++作对比,所以
	 * 就先不纠结这个了。在CPP文件下,声明完命名空间和头文件,用C语言的思维编写代码,这样写
	 * 也是完全没问题的。
	 */
}

void mainOP(FuncPT myp, int a, int b, char* p)
{
	(*myp)(a, b, p);
}

void main()
{
	mainOP(print1, 10, 5, "hello");
	system("pause");
}

声明一个函数指针类型FuncPT,以函数指针作为函数参数,编写一个函数
mainOP(FuncPT myp, int a, int b, char* p),调用mainOP()的时候,把要调用的函数指针作为实参传递进去,mainOP(print1, 10, 5, “hello”);,就可以成功调用print1(int a, int b,char* p),这样,经过mainOP()函数间接调用print1()函数,如果是单个函数调用,这样看似很蠢,但是这就是多态的原型。
然后升级一下,换成很多个函数:

typedef void(*FuncPT)(int a, int b, char* p);

void print1(int a, int b,char* p)
{
	cout << "result=" << a + b << p << endl;
}
void print2(int a, int b, char* p)
{
	cout << "result=" << a * b << p << endl;
}
void print3(int a, int b, char* p)
{
	cout << "result=" << a - b << p << endl;
}
void print4(int a, int b, char* p)
{
	cout << "result=" << a / b << p << endl;
}

void mainOP(FuncPT myp, int a, int b, char* p)
{
	(*myp)(a, b, p);
}

void main()
{
	mainOP(print1, 10, 5, "hello");
	mainOP(print2, 10, 5, "hello");
	mainOP(print3, 10, 5, "hello");
	mainOP(print4, 10, 5, "hello");
	system("pause");
}

增加3个print()函数,一字不动,不更改框架mainOP情况下,main()函数也可以通过mainOP调用新增的几个函数。这不就是多态吗,这跟多态的表现形式是完全一样的。主框架mainOP()函数不变,外面的子函数只要按照typedef void(FuncPT)(int a, int b, char p);提供的函数类型编写函数,不论以后增加多少个同类型的函数,还是减少,mainOP都可以原封不动,直接耦合。
和C++的关系映射:
mainOP()=== >主框架
typedef void(FuncPT)(int a, int b, char p); = =>父类虚函数或者纯虚函数,提前布局
print1(), print2(),print3(), print4()===>表示4个有继承关系的类里边函数原型相同的四个虚函数。
print1(), print2(),print3(), print4()的函数指针= =>每个函数的指针就是它所在的那个类里边虚函数表中的其中一个。
牛逼啊!!!!!!!!!!

工作中,因为做嵌入式工作,主要还是以C为主,就算是做Windows的图形界面的软件,也是首选C#,开发效率很高。实在是被C++的魅力深深吸引了,蹩脚复杂的语法下,理解透了,往往又是给自己打开了一扇新世界的大门。也尝试过用MFC来做图形界面,但是很快就放弃了,实在是太丑了!而且开发效率也不高。希望自己,不忘初心,能多学习一点。

以上很多知识都是查找资料,外加自己的理解总结而成的,肯定存在些许错误,如果哪位大神有发现错误的地方,请及时指正。
——冷亦花烟_CYB(菜蔡)
2019.2.25 23:28

你可能感兴趣的:(C语言,C++语言,多态)