C语言面向对象之继承、多态、可变参数、函数指针
来源:互联网 发布:电脑设计软件培训 编辑:程序博客网 时间:2024/05/29 14:01
最近要交一个小作业:用C语言实现类的封装、继承和多态,就顺手写一写吧。第一次写博客,若有错误之处,还望指教。内容有:
1. 类的定义(私有变量)
2. 类的方法(函数指针,构造/析构函数)
3. 类的继承(基类/派生类)
4. 多态(可变参数)
1. 类的定义
C++中用class来定义类,C语言可用struct结构体来表示类,使用另一个结构体变量来作为私有成员变量,使用函数指针作为类的方法。
// 作为私有变量的结构体struct PrivatePoint{ int x; int y;};// Point类typedef struct point{ struct PrivatePoint priPoint;}Point;
你或许也会发现,这样定义之后还是可以像point->priPoint.x这样直接访问私有变量x,这点和C++的私有的概念不同。我的理解是,这个“私有”的意思是,你可以将PrivatePoint的定义放在另一个.h文件中,而在Point类定义之处只需声明struct PrivatePoint; 没人知道该私有变量里面的内容。
2. 函数指针
函数指针是指向函数的指针变量,其声明格式为:
返回值类型 ( * 指针变量名) ([形参列表]);
在结构体中定义一个函数指针变量,表示类的方法;该方法在相应的.c文件中实现。此处以Shape类为例,后面会讲到Triangle类(三角形)和Circle类(圆形)作为其继承类。
// CClassBase.r#ifndef _CCLASSBASE_R_#define _CCLASSBASE_R_#include <stdarg.h>// 基类:形状,该类作为虚类typedef struct{ int size; // 结构体大小 // 构造函数 void* (*constructor)(const void *self, va_list *va); // 析构函数 void* (*destructor)(void *self); // 求面积函数 double (*area)(const void *self);}Shape;#endif
3. 继承
上述shape类作为基类,由于是虚类,其构造/析构函数并未实现,系统并不会实例化一个shape类对象。Triangle类、Circle类作为其继承类,当系统创建一个继承类的对象时,会调用相应的构造函数。
首先,定义继承类Triangle、Circle。
// CClassChildren.r#ifndef _CLASSCHILDREN_R_#define _CLASSCHILDREN_R_#include "CClassBase.r"// 三角形类,继承于形状类typedef struct{ const Shape shape; double sideLen;}Triangle;// 圆形类,继承于形状类typedef struct{ const Shape shape; double radius;}Circle;#endif
然后,实现基类的方法。
// CClassChildren.c#include "CClassBase.r"#include "CClassChildren.r"#include <math.h>#define PI 3.1415926//***************************** Triangle *******************************static void* Triangle_constructor(const void* _self, va_list* arg_ptr) { // Triangle类的构造函数 Triangle* self = (Triangle*)_self; self->sideLen = va_arg(*arg_ptr, double); return self;}static void* Triangle_destructor(void* _self){ // Triangle类的析构函数 return 0;}static double Triangle_area(const void* _self){ // Triangle类的求面积函数 Triangle* self = (Triangle*)_self; double len = self->sideLen; return sqrt(3.0) / 4 * len * len;}// 声明一个Triangle变量static const Shape _Triangle = { sizeof(Triangle), Triangle_constructor, Triangle_destructor, Triangle_area };const void* triangle = &_Triangle;//***************************** Circle ************************************static void* Circle_constructor(const void* _self, va_list* arg_ptr) { // Circle类的构造函数 Circle* self = (Circle*)_self; self->radius = va_arg(*arg_ptr, double); return self;}static void* Circle_destructor(void* _self){ // Circle类的析构函数 return 0;}static double Circle_area(const void* _self){ // Circle类的求面积函数 Circle* self = (Circle*)_self; double r = self->radius; return PI * r * r;}// 声明一个Circle变量static const Shape _Circle = { sizeof(Circle), Circle_constructor, Circle_destructor, Circle_area };const void* circle = &_Circle;
最后,在.h文件中声明继承类变量。上面的代码实现相当于对用户隐藏。
// CClassChildren.h#ifndef _CCLASSCHILDREN_H_#define _CCLASSCHILDREN_H_extern const void* triangle;extern const void* circle;#endif
看完这些之后会不会一头雾水呢?基类和继承类都定义好了,现在该考虑如何创建类的对象并调用其方法了。我们不妨想想C++是如何实现这些步骤的:首先new一个类对象 –> 调用该类的构造函数 –> 通过调用类的方法实现相应功能 –> 调用类的析构函数,销毁该类对象。
// CClassNew.hifndef _CCLASSNEW_H_#define _CCLASSNEW_H_#include <malloc.h>`#include <stdarg.h>#include <assert.h>#include "CClassBase.r"// 创建一个形状的类void* new_shape(const void* _self, ...){ const Shape* shape = (const Shape*)_self; void* p = calloc(1, shape->size); *(const Shape**)p = shape; if (shape->constructor) // 若定义了构造函数,则传参 { va_list va; va_start(va, _self); p = shape->constructor(p, &va); va_end(va); } return p;}// 销毁类void delete_shape(void* _self){ const Shape** shape = (const Shape**)_self; if (_self && shape && (*shape)->destructor) _self = (*shape)->destructor(_self); free(_self);}// 求形状的面积double area(const void* _self){ const Shape* const *p = (Shape**)_self; assert(_self && *p && (*p)->area); return (*p)->area(p);}#endif
这里的参数_self是指传进来的不同继承类,当调用该方法的时候,会根据不同的继承类来调用相应的类的方法,从而实现多态。
4. 多态
上面的new_shape、delete_shape、area函数根据不同的类调用不同的方法,就是实现多态。在程序中的具体调用如下:
// main.c#include <stdio.h>#include <stdlib.h>#include "CClassChildren.h"#include "CClassNew.h"int main(){ double a = 2.0, b = 1.0, c = 3.0; void * p = new_shape(triangle, a); printf("边长为 %.1f 的等边三角形面积为: %f\n\n", a, area(p)); delete_shape(p); p = new_shape(circle, b); printf("半径为 %.1f 的圆形面积为: %f\n\n", b, area(p)); delete_shape(p); return 0;}
这里补充一下可变参数的用法。说到可变参数,最常见的一个例子就是printf,其定义为int printf( const char* format, …); 省略号表示参数的个数不定。由此,一个具有可变参数的函数的定义格式为:
函数返回值 函数名(第一个参数, ...);
使用可变参数会用到以下宏,头文件为
void va_start( va_list arg_ptr, prev_param ); // 读取开始 type va_arg( va_list arg_ptr, type ); // 读取下一个参数 void va_end( va_list arg_ptr ); // 读取结束
这里的va_arg调用一次就读取下一个参数,无法计数。
// 例子void func(int param, ...){ va_list arg_ptr; va_start(arg_ptr, param); int i = va_arg(arg_ptr, int); // 读取第二个参数 int j = va_arg(arg_ptr, int); // 读取第三个参数 va_end(arg_ptr); printf("%d %d", i, j);}
参考如下:
http://blog.csdn.net/foruok/article/details/18192167
C语言中可变参数的用法
- C语言面向对象之继承、多态、可变参数、函数指针
- c语言之可变参数函数
- C/C++指针,多态,函数参数,面向对象抽象
- 面向对象之继承,封装,多态c语言实现
- c语言实现面向对象之继承,多态
- C和指针之函数之可变参数
- c语言可变参数函数
- C语言函数可变参数
- C语言可变参数函数
- C语言可变参数函数
- C语言可变参数函数
- C语言可变参数函数
- C语言可变参数函数
- C语言可变参数函数
- c语言之可变参数
- C语言之可变参数
- C 语言面向对象-- 继承
- C语言(Head First C)-8:高级函数:函数指针 qsort() 可变参数函数
- URI和URL的区别
- Sql Server远程连接数据库(相当于Oracle的dblink方式)
- Tomcat 7 中的 JDBC Realm 配置
- [svn] linux命令——svn分支创建、合并
- hdoj 2509 Be the Winner 【博弈】
- C语言面向对象之继承、多态、可变参数、函数指针
- Liunx sed
- CSS背景靠右对齐,并且背景图片右边刘10px
- Xcode7 collectionView的编辑新特性
- 【MySQL】【leetcode】 Rising Temperature解题报告
- Memcached源码分析(线程模型)
- 一款很好用的图片集左右滚动代码,可修改滚动宽度,总宽度,速度等
- Oracle 11g用exp无法导出空表的处理发布方法
- Python及第三方库api查看