环境:Linux Mint 17.1 32bit
GCC:(Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
第一步程序主入口main.c,代码如下
#include <stdio.h> int main(){ printf("Hello World\r\n"); return 1; }
编译执行
gcc main.c -o main ./main
输出:HelloWorld
第二步编写结构体PersonClass文件person.h,代码如下
typedef struct person{ int age; char* name } PersonClass;
第三步编写测试代码
#include <stdio.h> #include "person.h" int main(){ PersonClass p; p.name="Jack"; p.age=21; printf("HelloWorld\r\n"); printf("I am %s,i am %d",p.name,p.age); }
编译执行输出.
第四步编写子类Student完成继承
typedef struct student{ PersonClass p; void (*sayHello)(void); void (*setName)(char*,PersonClass*); void (*setAge)(int,PersonClass*); }StudentClass; void sayHello(){ printf("Good everybody\r\n"); } void setName(char* name,PersonClass* p){ p->name=name; } void setAge(int age,PersonClass* p){ p->age=age; }
上面代码中定义了三个函数指针,因为标准C结构体里面是不可以定义函数的,只能定义变量.
所以定义了两个所谓的Java中的setter函数,以及一个毫不相关的sayHello函数.
那么接着看如何使用.
#include <stdio.h> #include "person.h" #include "student.h" int main(){ PersonClass p; p.name="Jack"; p.age=21; printf("HelloWorld\r\n"); printf("I am %s,i am %d\r\n",p.name,p.age); StudentClass stu; stu.sayHello=&sayHello; stu.sayHello(); stu.setName=&setName;//初始化Setter stu.setName("ZhangHuiHui",&(stu.p)); stu.setAge=&setAge;//初始化Setter stu.setAge(0x28,&(stu.p)); printf("i am %s,i am %d\r\n",stu.p.name,stu.p.age); }
我们发现,在使用结构体Student时,如果采用面向对象的思想封装字段,是很痛苦的.至于继承,完全就是用一个Person成员变量来替代.但是因为C的不面向对象因素,我们在进行设置属性时,需要传递指针进去.
stu.p.name="ZhangHuiHui";//不面向对象去设置name
stu.setName("ZhangHuiHui",&(stu.p));//面向对象设置name(所谓的字段封装)
可以看出如果用C去实现封装字段,不是不可以,而是很繁琐.
假设有A,B ,C,D,四个结构体,并且继承关系如:D<C<B<A;
那么我们去封装字段去设置属性时,启不是要D.B.C.A.xxx=?;Or D.setXX(&(D.C.B.A));
C的特性决定了函数永远不可能归属于任何一个(跟面向对象最接近的)Struct;
C语言里指针才是霸主.但终究,面向对象是编程思想,而并非专属Java.
问题:我们直接在头文件里定义了setName setAge函数.如果我们在main.c中再定义一次呢?
不幸的是,我们不能再定义了,哪怕名字相同,形参不同也不允许.因为C不支持函数重载.
所以最大的问题是,C 没有包管理机制,函数名字就是唯一ID,不允许同名函数重复定义.