C++学习笔记:(七)C语言实现面向对象编程
面試官: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语言实现面向对象编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在Ubuntu下成功搭建以太坊私有链挖矿
- 下一篇: 区块链技术指南笔记(一):区块链基本概念