面试官:C和C++有什么不同?

应聘者:一个是面向过程,一个是面向对象。

这样的答案在我看是不完全正确,因为面向过程编程和面向对象编程是编程思想,C++可以用面向过程的思想编程,同样,C语言也可以用面向对象的思想编程。可能很少有人想过用C语言实现面向对象编程(真的麻烦,感觉就是吃力不讨好),但是,通过这样的尝试,可以使我们的学习过程更有意思。也能通过用C语言实现面向对象编程来深化对封装、继承、多态的理解(这是我个人的感觉)。以下的例子可能过于简单或不够全面(只实现了一部分),如果想再深入研究,建议上网百度相关的知识。

在学习如何使用C语言完成面向对象编程之前,先来看函数指针的用法。

#include <stdio.h>
char (*p)(int);
char Fun(int a)
{return a;
}int main()
{p = Fun;printf("%c\n",(*p)(75));return 0;
}

复习了函数指针,接下来尝试用C语言中实现C++中的类,类似于:

class Asd
{public:int a,b;int finda(){return a;}int findb(){return b;}int ab(){return a+b;}
};

具体实现如下:

#include <stdio.h>
#include <malloc.h>
struct Asd;
struct Asd_option//Asd类的函数成员
{int (*get_a)(struct Asd*);int (*get_b)(struct Asd*);int (*ab)(struct Asd*);
};typedef struct Asd//Asd类
{int a;//公有数据成员 int b;//公有数据成员struct Asd_option *a_option;//函数指针,指向的是操作
}Asd;int finda(struct Asd *s)//具体操作
{return s->a;
}
int findb(struct Asd *s)
{return s->b;
}
int findab(struct Asd *s)
{return (s->a)+(s->b);
}struct Asd_option qwe_option =
{finda,findb,findab
};//函数指针赋值struct Asd Asd_create(int x, int y)//Asd类的构造函数
{struct Asd asd;asd.a = x;asd.b = y;asd.a_option = &qwe_option;return asd;
}int main()
{Asd a = Asd_create(1,2);int x = a.a_option->get_a(&a);int y = a.a_option->get_b(&a);int z = a.a_option->ab(&a);printf("X:[%d] Y:[%d] Z:[%d]\n", x,y,z);printf("Asd_a:[%d]\n", a.a);return 0;
}

在C语言中,结构体就能完成简单的封装。因为结构体中是不能像C++类那样声明函数成员,所以要使用函数指针完成这一部分的功能。

struct Asd_option qwe_option =
{finda,findb,findab
}; 

这就是通过结构体对函数指针赋值。这样使得Asd类既有数据成员,又有函数成员。

上面的例子完成了最简单的封装,而且数据成员都是公有的,接下来实现保护或私有数据成员,类似于:

class Asd
{
private:int x,y;
public:int a,b;int findx(){return x;}int findy(){return y;}int xy(){return x+y;}
};
#include <stdio.h>
#include <malloc.h>
struct Asd;
struct Asd_option//可以设为保护成员也可以设为私有成员
{int x;int y;int (*get_x)(struct Asd*);int (*get_y)(struct Asd*);int (*xy)(struct Asd*);
};typedef struct Asd//Asd类
{int a;int b;struct Asd_option *a_option;//函数指针
}Asd;int findx(struct Asd *s)//具体操作
{return s->a_option->x;
}
int findy(struct Asd *s)
{return s->a_option->y;
}
int findxy(struct Asd *s)
{return (s->a_option->x)+(s->a_option->y);
}struct Asd_option qwe_option =
{0,0,findx,findy,findxy
};//函数指针赋值Asd Asd_create(int m, int n)//Asd类的构造函数
{struct Asd asd;asd.a = 3;asd.b = 4;asd.a_option = &qwe_option;asd.a_option->x = m;asd.a_option->y = n;return asd;
}int main()
{Asd a = Asd_create(1,2);int x = a.a_option->get_x(&a);int y = a.a_option->get_y(&a);int z = a.a_option->xy(&a);printf("X:[%d] Y:[%d] Z:[%d]\n", x,y,z);printf("Asd_a:[%d]\n", a.a);printf("Asd_b:[%d]\n", a.b);//printf("Asd_x:[%d]\n", a.x);     //printf("Asd_y:[%d]\n", a.y);     //x,y保护(或私有)数据成员,不能直接访问return 0;
}

接下来实现简单的重载多态:

#include <stdio.h>
#include <stdlib.h>
typedef struct intasd
{int a;int b;
}Int_asd;typedef struct floatasd
{float x;float y;
}Float_asd;typedef void* (*Addfunction)(void*); //typedef定义函数指针的语法:typedef 返回类型 (*指针名)(参数表)void* intadd(void *asd)
{Int_asd *s = (Int_asd*)asd;int amount = s->a + s->b;printf("Result: = [%d]\n", amount) ;
}void* floatadd(void *asd)
{Float_asd *s = (Float_asd*)asd;float amount = s->x + s->y;printf("Result: = [%f]\n", amount) ;
}void* Add(Addfunction f, void *asd)
{return f(asd);
}int main()
{Int_asd x = {1, 2};Float_asd y = {1.1, 2.2};Add(intadd, &x);Add(floatadd, &y);return 0;
}

实现继承和包含多态:

#include <stdio.h>
#include <malloc.h>
#include <math.h>
struct Shape;
struct Shape_option
{float (*area)(struct Shape*);/*返回几何体的面积*/int (*perimeter)(struct Shape*);/*返回几何体的周长*/
};typedef struct Shape //基类
{char* Shape_name;struct Shape_option *Shape_ops; /*虚函数,功能由子类实现*/
}Shape;float Shape_area(struct Shape* s)/*求形状面积*/
{return s->Shape_ops->area(s);
}int Shape_perimeter(struct Shape* s) /*求周长*/
{return s->Shape_ops->perimeter(s);
}typedef struct triangle/*三角形类*/
{Shape Base;//公有继承int a;int b;int c;
}Triangle;float Triangle_area(struct Shape* s)/*三角形面积,用海伦公式*/
{Triangle *t = (Triangle*)s;int x = t->a;int y = t->b;int z = t->c;float p = (x+y+z)/2;return sqrt(p*(p-x)*(p-y)*(p-z));
}int Triangle_perimeter(struct Shape* s)/*三角形周长*/
{Triangle* t = (Triangle*)s;int x = t->a;int y = t->b;int z = t->c;return x+y+z;
}struct Shape_option triangle_ops =/*对父类虚函数的实现*/
{Triangle_area,Triangle_perimeter
};Triangle* Triangle_create(int x,int y,int z)/*三角形构造函数*/
{Triangle* ret = (Triangle*)malloc(sizeof (*ret));ret->Base.Shape_name = "triangle";ret->Base.Shape_ops = &triangle_ops;ret->a = x;ret->b = y;ret->c = z;return ret;
}typedef struct rectangle/*矩形类*/
{Shape Base;//公有继承int width;int height;
}Rectangle;float Rectangle_area(struct Shape* s)/*矩形函数成员*/
{Rectangle* r = (Rectangle*)s;return r->width * r->height;
}int Rectangle_perimeter(struct Shape* s)/*矩形函数成员*/
{Rectangle* r = (Rectangle*)s;return (r->width+r->height)*2;
}struct Shape_option rectangle_ops =/*对父类虚函数的实现*/
{Rectangle_area,Rectangle_perimeter
};Rectangle* Rectangle_create(int width, int height)/*矩形构造函数*/
{Rectangle* ret = (Rectangle*)malloc(sizeof(*ret));ret->Base.Shape_name = "rectangle";ret->Base.Shape_ops = &rectangle_ops;ret->height = height;ret->width = width;return ret;
}int main()
{Shape *s[4];s[0] = (Shape*)Triangle_create(5,5,4);s[1] = (Shape*)Triangle_create(3,4,5);s[2] = (Shape*)Rectangle_create(10,12);s[3] = (Shape*)Rectangle_create(5,8);int i=0;for(i=0 ;i<4 ;i++){float area = Shape_area(s[i]);int perimeter = Shape_perimeter(s[i]);char *name = s[i]->Shape_name;printf("name:%s ,area:%.2f ,perimeter:%d\n",name,area,perimeter);}return 0;
}

Shape是基类,Triangle类继承基类Shape,并新增数据成员a、b、c,实现简单的继承。上述例子中,子类对父类虚函数进行实现,实现了包含重载。虽然上面的结果可能不能像C++所展示的那样,但是思想上是面向对象的。

运算符重载将重载的概念扩展到运算符上,允许赋予C++运算符多种含义。实际上,C++(包括C语言)运算符已经被重载。例如,将*运算符用于地址,将得到存储在这个地址中的值;但将它用于两个数字时,得到的将是他们的乘积。

参考:http://blog.chinaunix.net/uid-26921272-id-3360269.html

C++学习笔记:(七)C语言实现面向对象编程相关推荐

  1. JavaScript学习笔记(十一):面向对象编程

    一.关于面向对象 编程可以分为面向过程编程和面向对象编程 面向过程:就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用 面向对象:把一件事分解成一个个对象 ...

  2. 《objective-c基础教程》学习笔记(四)—— OC面向对象编程初探

    在上篇博文中,我们编写了一个可以输出不同几何类型的小程序.通过C语言的struct结构体,给大家感受了下,对象的大概样子. 如果用Obejctive-C的面向对象的特征来实现.那么,drawShape ...

  3. 2022Java学习笔记八十八(网络编程:UDP通信,一发一收,多发多收消息接收实现)

    2022Java学习笔记七十八(网络编程:UDP通信,一发一收,多发多收消息接收实现) 一.快速入门 DatagramPacket:数据包对象 实例代码 定义发送端 package com.zcl.d ...

  4. 23 DesignPatterns学习笔记:C++语言实现 --- 2.2 Adapter

    23 DesignPatterns学习笔记:C++语言实现 --- 2.2 Adapter 2016-07-22 (www.cnblogs.com/icmzn) 模式理解 1. Adapter 定义 ...

  5. Java快速入门学习笔记9 | Java语言中的方法

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  6. Java快速入门学习笔记7 | Java语言中的类与对象

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  7. 逆向脱壳破解分析基础学习笔记七 堆栈图(重点)

    本文为本人 大神论坛 逆向破解脱壳学习笔记之一,为本人对以往所学的回顾和总结,可能会有谬误之处,欢迎大家指出. 陆续将不断有笔记放出,希望能对想要入门的萌新有所帮助,一起进步 堆栈图 首先给定一段反汇 ...

  8. 【学习笔记】C++语言程序设计(郑莉):多态性

    [学习笔记]C++语言程序设计(郑莉):多态性 1. 多态性 2. 运算符重载 2.1 运算符重载的规则 2.2 运算符重载为成员函数 2.3 运算符重载为非成员函数 3. 虚函数 3.1 一般虚函数 ...

  9. Python学习笔记(十九)面向对象 - 继承

    Python学习笔记(十九)面向对象 - 继承 一.继承的概念 # 继承:子类继承父类的所有方法和属性# 1. 子类 class A(object):def __init__(self):self.n ...

最新文章

  1. 中体骏彩C++面试题
  2. AMS重要的数据结构解析(三):ActivityStack
  3. 皮一皮:成人世界的潜台词...
  4. 【MM模块】Releasing Blocked Invoices 释放冻结发票
  5. 推荐系统——开源代码
  6. 【Mongodb】用户和认证 权限总结
  7. scipy是python下的什么_SciPy是什么
  8. 计算机数学基础模拟试题,计算机数学基础》模拟考试试题.doc
  9. 551. 学生出勤记录 I
  10. C++学习日记#3——追赶法求解系数矩阵为对角占优的三对角线方程组
  11. 雷士灯wifi控制方法_雷士照明驱动 WiFi 可调光 怎么设置
  12. 小小技巧--BLOB视频加密
  13. DIV+CSS学习笔记总结篇
  14. 《30天自制操作系统》-day2(MAC)
  15. Unbuntu20.04环境下一款开源翻译软件:goldendict的安装与配置(图文)
  16. 【人工智能】人脸识别系统【实验报告与全部代码】(QDU)
  17. 为任意屏幕尺寸构建 Android 界面
  18. KnockoutJs 进阶学习
  19. PDF合并:如何将两个PDF文件合并成一个PDF文件
  20. 适用于异构芯片(CPU,ASIC,DSP,FPGA,GPU)的软件并行技术

热门文章

  1. cocos2d-x游戏实例(4)-地图碰撞
  2. EV3 直接命令 - 第 4 课 用两个驱动轮精确地移动小车
  3. 如何优雅的设计和使用缓存?
  4. MyBatis(二)MyBatis基本流程源码分析
  5. 深入理解Java内存架构
  6. 【今晚七点半】:多媒体开源PI
  7. @你最强资源包来了 MobTech 联合 LiveVideoStack 发起劳动光荣榜
  8. 基于Open WebRTC Toolkit(OWT)的8K全景视频低延时直播系统
  9. 基于Nginx的媒体服务器技术
  10. Wireshark安装和基本使用