个人水平比较粗浅,想以一个初学者的角度,以C的方式去看待C++面向对象。
采用循序渐进,慢慢摸索的方式来学习,其实我也是边写边想,还会参考一些资料,有不足请指正。希望帮助自己,帮助大家更加深刻理解面向对象。
只想和大家分享,不喜勿喷,请多指教,感激不尽。
-----------------------------------正文------------------------------------
在学习面向对象时候,封装应该是我们第一个接触的特性。
说到C++中的class,很自然就想到了在C里面和他对应的关键字struct
为了使函数也能够放在struct里面,我们自然联想到了函数指针。
比如一个公司的职员类,包括姓名,工资,以及操作函数——显示职员信息。
typedef struct Employee
{
char name[20];
int salay;
void (*Print)();
}Date;
但是我们知道,class里面其实有一个隐藏指针this用来指向本类,并且每个成员函数都有一个隐藏的常量参数this。
所以最终代码是这样
typedef struct Employee
{
struct Employee *This;
char name[20];
int salay;
void (*Print)(const struct Employee);
}Employee;
void Print(const struct Employee *This)
{
printf("My Name is %s\n",This->name);
}
对了,我们需要一个构造函数,来对结构体中的函数指针初始化。
要怎么写呢?。。。。
先想想我们在main函数里面这么调用的吧,在C++里面我们希望是
int main()
{
Employee a;
a.Print();
return 0;
}
为了尽量仿照,我觉得应该是这样的调用:
int main()
{
Employee a=EmployeeInit();
a.Print(&a);
return 0;
}
这下知道该怎么写了吧。
Employee EmployeeInit()
{
Employee *p = (Employee *)malloc(sizeof(Employee));
strcpy(p->name,"Li Hua");
p->salay = 1000;
p->This =p; //初始化This指针
p->Print = Print; //这里初始化函数指针
return *p;
}
这其实就是类中的构造函数的实现。有了构造函数,当然得有析构函数,要不然得内存泄露了。在C++中自动调用这些,而现在我们得手动调用了。
最后代码是这样的:
typedef struct Employee
{
struct Employee *This;
char name[20];
int salay;
void (*Print)(const struct Employee*);
}Employee;
void Print(const struct Employee *This)
{
printf("My Name is %s\n",This->name);
printf("My Salay are %d\n",This->salay);
}
Employee EmployeeInit()
{
Employee *p = (Employee *)malloc(sizeof(Employee));
strcpy(p->name,"Li Hua");
p->salay = 1000;
p->This =p; //初始化This指针
p->Print = Print; //这里初始化函数指针
return *p;
}
bool EmployeeDestructor(Employee x)
{
free(x.This);
return true;
}
int main()
{
Employee a=EmployeeInit();
a.Print(a.This);
EmployeeDestructor(a);
return 0;
}
运行结果
但是这里遇到一个问题,我们虽然通过这种办法把数据和操作放在一块儿了,但是没有体现到数据保护,我们仍然能够访问到私有成员name和salay,这不符合封装的思想。
(我们并不想外界访问到name,salay这些数据)
所以我们要想办法实现C++里面的访问控制符,private,public。
想了挺久,决定用2个类共同来实现,一个类用来存放私有的,另一个类来放public接口,对外只公开public。
对了,顺便改一下构造函数。C里面木有函数重载,只能有一个构造函数是硬伤啊。
最终代码变成这样了:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//这个结构体是私有的,相当于private成员,不允许创建对象
typedef struct Employee_P
{
char name[20];
int salay;
}Employee_P;
//相当于public的成员
typedef struct Employee
{
struct Employee_P *This; //This指针也得放到类里面
void (*Print)(const struct Employee*); //包含函数指针,用来访问这个函数
}Employee;
void Print(const struct Employee *This)
{
Employee_P *it = This->This;
printf("My Name is %s\n",it->name);
printf("My Salay are %d\n",it->salay);
}
/*构造函数*/
Employee EmployeeInit(char *name,int salay)
{
Employee ret;
Employee_P *p =(Employee_P *)malloc(sizeof(Employee_P));
strcpy(p->name,name);
p->salay = salay;
ret.This =p; //初始化This指针
ret.Print =Print; //这里初始化函数指针,让它指向Print这个函数
return ret;
}
/*析构函数*/
bool EmployeeDestructor(Employee x)
{
free(x.This);
return true;
}
int main()
{
Employee a=EmployeeInit("Li Hua",1000);
Employee b=EmployeeInit("Xiao Meng",10000);
a.Print(&a);
b.Print(&b);
EmployeeDestructor(a);
EmployeeDestructor(b);
return 0;
}
现在,我们只能访问到a的对外接口了。
这样我们的a对象就不能访问到name,salay了。
如果别人无聊一定要创建一个Employee_P 类来访问你的成员。
你还可以分成多个文件,然后只把Employee 的声明放在文件里面,对外公开Employee.h 的头文件,这样别人就找不到你的Employee_P声明和定义,想创建也创建不了了(我没试过,猜测的,不负责任)。
最终,虽然有点别扭,但是面向对象的一大特性,封装,就这么被我们实现了。(貌似是最简单的)