C++语言基本语法中包含了面向对象的三大特性:封装,继承,多态。正是因为C++在语法层面上支持了这些面向对象特性,才使得大型项目会考虑用此语言来搭建平台或产品框架。其实也可以这样说,面向对象是相对于面向过程而言的,更多地是一种思维方式,世间万物皆对象,感觉跟毕达哥拉斯学派宣称那样:万物皆数。所以面向对象作为一种软件设计方式(当然面向对象还有独特的SOLID设计原则),其他语言完全可以借用,比如说C语言就可以。我们在linux内核代码中就可以经常看到面向对象的特性。比如文件操作中将属性与方法(一般定义为函数指针)封装到特定结构体中。我们知道,C++与C一样,是一门静态语言,当代码编译后,其函数地址就相对固定了,那是怎么通过运行时来改变函数行为的呢? C++教科书中有介绍说,多态是通过虚函数实现的。如果在基类某些函数前面声明为virtual,则C++编译器会在内存对象模型前面插入一个虚函数指针,该指针指向一个虚函数表,正是因为我们可以改变虚函数指针所指函数表地址,从而实现其多态操作。下面我们以一个简单的示例来用C实现C++的继承与多态特性。
/*
*
*C语言实现C++面向对象多态特性
* Created on: 2015年12月26日
* Author: @CodingGeek
*/
#include <stdio.h>
#include <stdlib.h>
struct base;
struct base_vtbl
{
void(*dance)(struct base *);
void(*jump)(struct base*, int high);
};
struct base
{
struct base_vtbl *vptr;
/*base members */
};
void base_dance(struct base *pb)
{
pb->vptr->dance(pb);
}
void base_jump(struct base *pb, int high)
{
pb->vptr->jump(pb, high);
}
void based_dance(struct base *pb)
{
printf("base dance\n");
}
void based_jump(struct base *pb, int high)
{
printf("base jump:%d\n", high);
}
/* global vtable for base */
struct base_vtbl base_table =
{
based_dance,
based_jump
};
void base_init(struct base *pb)
{
pb->vptr = &base_table;
}
struct derived1
{
struct base super;
/*derived members */
};
void derived1_dance(struct derived1 *pd)
{
/*implementation of derived1's dance function */
printf("derived1 dance\n");
}
void derived1_jump(struct derived1 *pd, int high)
{
/*implementation of derived1's jump function */
printf("derived1 jump:%d\n", high);
}
/*global vtable for derived1 */
struct base_vtbl derived1_table =
{
(void(*)(struct base *))&derived1_dance,
(void(*)(struct base*, int))&derived1_jump
};
void derived1_init(struct derived1 *pd)
{
pd->super.vptr = &derived1_table;
/*init base members d->super.foo */
/*init derived1 members d->foo */
}
struct derived2
{
struct base super;
/*derived2 members */
};
void derived2_dance(struct derived2 *pd)
{
/*implementation of derived2's dance function*/
printf("derived2 dance\n");
}
void derived2_jump(struct derived2 *pd, int high)
{
/*implementation of derived2's jump function */
printf("derived2 jump:%d\n", high);
}
/*global vtable for derived2 */
struct base_vtbl derived2_table =
{
(void(*)(struct base *))&derived2_dance,
(void(*)(struct base*, int))&derived2_jump
};
void derived2_init(struct derived2 *pd)
{
pd->super.vptr = &derived2_table;
/*init base members d->super.foo */
/*init derived1 members d->foo */
}
int main(void)
{
/*OK~! We're done with our declarations, now we can finally do
* some polymorphism in C
*/
/*这里类似C++等面向对象语言的构造函数,初始化内存模型,包括了虚函数指针初始化等*/
struct base b;
base_init(&b);
struct base *b_ptr = (struct base*)&b;
base_dance(b_ptr);
base_jump(b_ptr, 99);
struct derived1 d1;
derived1_init(&d1);
struct derived2 d2;
derived2_init(&d2);
/*这里看作是类型转换,C语言中只有强制转换,或者类型隐式提升,对应于C++的
* reinterpret_cast,当然C++还有static_cast与dynamic_cast等类型转化
*/
struct base *b1_ptr = (struct base *)&d1;
struct base *b2_ptr = (struct base *)&d2;
/*这里实际上间接引用的就是子类的函数地址*/
base_dance(b1_ptr); /*calls derived1_dance */
base_jump(b1_ptr, 88);/*calls derived1_jump */
base_dance(b2_ptr); /*calls derived2_dance */
base_jump(b2_ptr, 77); /*calls derived2_jump */
return 0;
}
从上面运行结果可以看出,C语言实现多态的特性是没有问题的,问题在于我们如何建立抽象模型(实际上类似C++内存对象模型)。而C++恰好原生支持了这一切,不需要我们重复造轮子了。
原文地址: https://blog.csdn.net/sunjunior/article/details/50838143