封装的要素
C++中对一个类中的数据及接口有属性的描述, : public, private, protected
三种. 本文采用C语言的方式实现三种属性
实现private封装
private属性, 只有本类内部可使用, 即不对外开放, 也不对子类开放
C语言中声明的struct的属性都是public属性
如:
在c_elephant.h中声明
struct Elephant{
int weight;
int height;
int width;
char* name;
};
这样无法达到private的效果. 所以改为在.h中声明, 在.c中实现
c_elephant.h
#ifndef __C_ELEPHANT_H__
#define __C_ELEPHANT_H__
//仅做声明, 这样还有一个好处, 外部无法直接定义使用这个类,
//必须调用我们手写的构造函数才能获得此类的对象.
typedef struct Elephant c_elephant_private;
#endif
c_elephant.c
#include "c_elephant.h"
#include "stdlib.h"
#include "string.h"
struct Elephant{
//private
int weight;
int height;
int width;
char* name;
};
这样无法在外部获取内部成员:
main.c
#include <stdio.h>
#include "c_elephant.h"
int main(int argc, char **argv)
{
c_elephant_private elephant; //编译报错
printf("name : %s\n", elephant.name);//编译报错
return 0;
}
实现构造函数,析构函数,private方法, public方法
要使用c_elephant, 必须使用给定的构造函数来获得完整对象:
c_elephant.h
#ifndef __C_ELEPHANT_H__
#define __C_ELEPHANT_H__
//仅做声明, 这样还有一个好处, 外部无法直接定义使用这个类,
//必须调用我们手写的构造函数才能获得此类的对象.
typedef struct Elephant c_elephant_private;
//声明构造函数
c_elephant_private *c_class_elephant_newElephant(int weight, int height, int width, const char* name, const int length);
//声明析构函数
void c_class_elephant_free(c_elephant_private* this_ptr);
//声明一个public方法, 返回对外私有数据
char* getName(c_elephant_private* this_ptr);
#endif
private方式是由本类能使用, 所以只需要在.c中对函数声明加static关键字即可.:
c_elephant.c
#include "c_elephant.h"
#include "stdlib.h"
#include "string.h"
struct Elephant{
//private
int weight;
int height;
int width;
char* name;
};
//private方法
static void c_elephant_initName(c_elephant* p, const char* name, const int length);
//实现构造函数
c_elephant_private *c_class_elephant_newElephant(int weight, int height, int width, const char* name, const int length)
{
c_elephant_private *new_c_elephant = (c_elephant_private *) malloc(sizeof(c_elephant));
c_elephant_initName(new_c_elephant, name, length);
new_c_elephant->height = height;
new_c_elephant->width = width;
new_c_elephant->weight = weight;
return new_c_elephant;
}
static void c_elephant_initName(c_elephant* this_ptr, const char* name, const int length)
{
this_ptr->name = (char *) malloc((length + 1) * sizeof(char));
memset(this_ptr->name, 0, length+1);
strncpy(this_ptr->name, name, length);
}
//实现析构函数
void c_class_elephant_free(c_elephant_private* this_ptr)
{
free(this_ptr->name);
free(this_ptr);
this_ptr = NULL;
}
char* c_class_elephant_getName(c_elephant_private* this_ptr)
{
return this_ptr->name;
}
main.c
#include <stdio.h>
#include "c_elephant.h"
int main(int argc, char **argv)
{
//只有调用构造函数才能获取完整的对象
c_elephant_private *c_class_elephant = c_class_elephant_newElephant(20, 30, 40, "1234", 4);
printf("name : %s\n", c_class_elephant_getName(c_class_elephant));//输出1234
c_elephant_free(c_class_elephant);
return 0;
}
对public方法进行改造, 并添加public数据
在前面的代码中会发现, 此时的c_elephant_private添加所有的数据都是private, 无法添加public数据的, 以及对于public方法c_class_elephant_getName实际上是一个全局函数外部可见, 不符合封装思想
所以需要将 私有数据隔离开, 将public包含进类中
最终得到的代码
c_elephant.h
#ifndef __C_ELEPHANT_H__
#define __C_ELEPHANT_H__
//作为类中私有数据不对外开放
typedef struct Elephant c_elephant_private;
typedef struct class_elephant{
//作为对外开放的方法
char* (*getName)(struct class_elephant* this_ptr);
c_elephant_private *private_data;
} c_class_elephant;
//构造函数
c_class_elephant *c_class_elephant_newElephant(int weight, int height, int width, const char* name, const int length);
//析构函数
void c_class_elephant_free(c_class_elephant* this_ptr);
#endif
c_elephant.c
#include "c_elephant.h"
#include "stdlib.h"
#include "string.h"
struct Elephant{
//private
int weight;
int height;
int width;
char* name;
};
//private:
static void c_class_elephant_init_private(c_class_elephant *ptr, int weight, int height, int width, const char* name, const int length);
static void c_elephant_private_initName(c_elephant_private* p, const char* name, const int length);
//public 构造函数
c_class_elephant *c_class_elephant_newElephant(int weight, int height, int width, const char* name, const int length)
{
c_class_elephant *new_c_class_elephant = (c_class_elephant *) malloc(sizeof(c_class_elephant));
c_class_elephant_init_private(new_c_class_elephant, weight, height, width, name, length);
new_c_class_elephant->getName = &c_class_elephant_private_getName;
return new_c_class_elephant;
}
static void c_class_elephant_init_private(c_class_elephant *ptr, int weight,
int height, int width,
const char* name, const int length)
{
ptr->private_data = (c_elephant_private *) malloc(sizeof(c_elephant_private));
c_elephant_private_initName(ptr->private_data, name, length);
ptr->private_data->height = height;
ptr->private_data->width = width;
ptr->private_data->weight = weight;
}
static void c_elephant_private_initName(c_elephant_private* this_ptr, const char* name, const int length)
{
this_ptr->name = (char *) malloc((length + 1) * sizeof(char));
memset(this_ptr->name, 0, length+1);
strncpy(this_ptr->name, name, length);
}
//public 析构函数
void c_class_elephant_free(c_class_elephant* this_ptr)
{
free(this_ptr->private_data->name);
free(this_ptr->private_data);
free(this_ptr);
this_ptr = NULL;
}
//public 方法
char *c_class_elephant_private_getName(c_class_elephant* this_ptr)
{
return this_ptr->private_data->name;
}
main.c
#include <stdio.h>
#include "c_elephant.h"
int main(int argc, char **argv)
{
c_class_elephant* C_class_elephant = c_class_elephant_newElephant(20, 30, 40, "1234", 4);
printf("name: %s\n", C_class_elephant->getName(C_class_elephant));
c_class_elephant_free(C_class_elephant);
return 0;
}