前言
面向对象三大特性是 封装 - 继承 - 多态
面向对象三大特性 :
- 封装 ( Encapsulation ) : 将 数据 和 操作数据的方法 包装在一起 , 隐藏 数据的内部细节 , 防止外界的直接访问和修改 ;
封装后 , 只能通过 对外提供的接口 , 对 封装在内部的属性和方法 进行 访问和操作 ; - 继承 ( Inheritance ) : 让 一个 实例对象 获取 另一个 实例对象 的 属性 和 方法 , 在不重写现有代码的基础上实现代码的重用 ;
继承可以 实现出 类的层次结构 , 可以 扩展 现有父类的功能 ; - 多态 ( Polymorphism ) : 不同的 实例对象 对 想通的消息 作出不同响应 , 也就是调用想通类型实例对象 的 方法 有不同的行为 ;
多态 通过 方法的 重载 ( Overloading ) 和 虚函数 ( Virtual Function ) 实现 ;
多态 可以 提高代码的 灵活性 和 可维护性 , 使代码更加易于扩展和修改 ;
许多面向对象的程序设计语言都提供了较好的信息隐藏的手段,例如C++,JAVA。他们通过在类(Class)中,对访问权限进行限制,以公有(Public),私有(Private)等标签规定了一套访问规则(当然,还有protected),从而实现了信息隐藏。
那么,在C语言这样的面向过程的程序设计语言中,我们怎么来封装自己的抽象数据类型呢?
我们知道,C语言提供了struct关键字,可以让我们将一组各种类型的集合打包成一种新的类型。
但是怎么才能隐藏 struct结构体的内部细节 , 防止外界的直接访问和修改呢?这就需要提及:C语言特性的不透明指针。
C语言特性:不透明指针
C语言有这样一个特性,它允许我们在给出一个结构体(struct)的定义之前,先声明指向它的指针(Pointer)
下面的代码可以在mingw32-4.5.2编译器中编译通过。
int main (int argc, char * argv[])
{
struct some_struct * p; /*p是一个指向struct some_struct的指针,但我们并不知道struct some_struct是什么,它都有哪些成员*/
return 0;
}
该段代码可以顺利地通过编译,说明这样的声明确实是被允许的。然而,当我们继续,进行解引用的时候:
int main (int argc, char * argv[])
{
struct some_struct * p; /*p是一个指向struct some_struct的指针,但我们并不知道struct some_struct是什么,它都有哪些成员*/
p->some_attribute; /*现在我们对p解引用,希望获得它的some_attribute这个属性*/
return 0;
}
这时编译器会向我们报错:error: dereferencing pointer to incomplete type (错误:对指向不完整类型的指针进行解引用)
这时,用户看不见struct内部的具体细节了。
注意:在给出一个结构体的定义之前,先声明指向它的指针,但并不代表我没有定义这个结构体,只是定义在了其他的地方(其他的文件)中
利用不透明指针实现“封装”特性
student.h文件
#ifndef _STUDENT_
#define _STUDENT_
typedef struct stu *student_t; /*声明一种新的类型叫做student_t,它是一个指向struct stu的指针*/
student_t new_student(char *name, int age, double grade);
void delete_student(student_t student);
char* get_student_name(student_t student);
int get_student_age(student_t student);
#endif
student.c文件
#include "student.h"
#include <stdlib.h>
#include <string.h>
struct stu /*定义了结构体struct stu的具体内容*/
{
char name[28];
int age;
double grade;
};
student_t new_student(char *name, int age, double grade)
{
student_t p = malloc(sizeof(struct stu));
if (p != NULL)
{
strcpy(p->name, name);
p->age = age;
p->grade = grade;
}
return p;
}
void delete_student(student_t student)
{
if (student!= NULL)
{
free(student);
}
}
int get_student_age(student_t student)
{
if (student!= NULL)
{
return student->age;
}
return -1;
}
char* get_student_name(student_t student)
{
if (student!= NULL)
{
return student->name;
}
return NULL;
}
main.c文件
#include "student.h"
#include <stdio.h>
int main(void)
{
student_t stu1;
stu1 = new_student("zhangsan", 18, 0);
printf("student age: %d\n", get_student_age(stu1));
printf("student name: %s\n", get_student_name(stu1));
return 0;
}
运行结果: