1.C语言实现封装
在C语言当中,是不存在封装这一个特性的,我们要实现它,我们可以借助两个方法:
1.利用C语言中的头文件,在头文件中进行声明,在C文件中对它进行定义,这样就可以隐藏内部信息,用户只能看到接口和公开的信息,无法知道对象所占内存等。
示例代码:
头文件:
#define _CRT_SECURE_NO_WARNINGS 1
//在这里,头文件中给出了声明,用户只能看到公有部分和函数接口。
#ifndef POINT_H
#define POINT_H
#include<stdio.h>
#include<stdlib.h>
struct Point;
typedef struct Point point;
point * new_project();//创建对象
void free_point(point *point_);//释放空间
#endif
源文件:
#define _CRT_SECURE_NO_WARNINGS 1
#include"封装1.h"
struct Point //结构体中存在成员变量
{
int x;
int y;
};
point *new_point()//相当于是一个构造函数
{
point *new_point_ = (point *)malloc(sizeof(point));
return new_point_;
}
void free_point(point *point_)//相当于是一个析构函数
{
if (point_ != NULL)
{
free(point_);
}
return ;
}
2.第二种方法是把私有的信息放在一个不透明的私有变量或者结构体当中,只有类的实现代码才知道priv或者结构体的真正定义。
头文件:
//在这向用户提供接口。通过这些接口,可以访问到私有成员变量,x和y,还有用来创建初始化对象的构造函数,释放销毁对象的析构函数。
#ifndef POINT_H
#define POINT_H
#include<stdio.h>
#include<cstdlib>
typedef struct Point point;
typedef struct pointPrivate pointPrivate;
struct Point
{
struct pointPrivate *pp;
};
int get_x(point *point_);
int get_y(point *point_);
point * new_point;//创建新的对象;
void free_point(point *point_);//释放对象开辟的空间
#endif //!POINT_H
源文件:
#include"封装2.h"
//在这给出了两个成员变量,另外两个函数都是通过指针访问成员变量
struct pointPrivate
{
int x;
int y;
};
int get_x(point* point_)
{
return point_->pp->x;
}
int get_y(point* point_)
{
return point_->pp->y;
}
简单说,C语言实现封装,就是需要进行一些信息的隐藏,对用户只需要提供接口就好了。
2.C语言实现继承
继承,简单来说就是子类对父类代码的复用,所以要是想简单的进行实现,最简单就是使用结构体嵌套了。
struct Base
{
int b;
};
struct Derived
{
struct Base b;
int d;
};
void test1()
{
Derived d;
}
在这里我们了解到,在派生类Derived的对象d中存在基类Base的内容,并且有他自己的内容。
关于继承,最重要的额就是隐藏,重写(覆盖),重载还有虚函数,除了重载以外,其他都可以实现,重载是因为C语言编译器调用约定的原因,不支持,但是这个也影响不大。
由于C中呢没有访问限定,所以在C语言中我们只能实现公有继承。
我们需要像C++中一样可以通用过对象来访问成员函数,这种实现可以采用函数指针,又因为C语言中是没有this指针的,所以我们应该给函数传递一个this指针,就是自身的指针。
另外,我们需要自己写一个构造函数,用来开辟空间。
实现继承需要的功能:
首先我们给出基类和派生类
struct base
{
int a;
void(*func1)(struct base *_this);
};
struct derived
{
struct base parent;
int b;
void(*fun2)(struct derived *_this);
};
然后我们给出两个函数:
static void base_func1(struct base *_this)
{
printf("this is base::func1\n");
}
static void derived_func1(struct derived * _this)
{
printf("this is derived::func2\n");
}
然后按照我们写类时的流程,我们写出基类构造函数
struct base * new_base()//构造函数
{
struct base * b = malloc(sizeof(struct base));//开辟空间
b->a = 0;
b->func1 = base_func1;//让函数指针指向函数。
return b;
}
这样,我们就可以通过函数指针,访问到成员
struct base*b1 = new_base();
b1->func1(b1);
我们通过_this指针来访问所指向的成员变量,派生类能够访问基类的public和protected成员。
static void derived_func2(struct derived *_this)
{
//显式的来访问_this指针所指向的成员变量
printf("this is derived::func2, base::a = %d\n", _this->parent.a);
_this->parent.func1(&_this->parent);
}
struct derived * new_derived()
{
struct derived * d = malloc(sizeof(struct derived));
d->b = 0;
d->fun2 = derived_func2;
return d;
}
然后,我们可以使用派生类对象可以访问基类成员和派生类对象前提只能通过派生类对象
struct derived d;
printf("base::a=%d\n", d.parent.a);
struct derived *p = new_derived();
((struct base *)p)->func1(p);
对于被派生类覆盖的基类的非虚函数,在派生类中可以通过基类名和域作用符::来访问
struct derived * d = new_derived();
d->func(d);
d->b.func((struct base*)d);
因为这里的继承实际上是通过派生类中存在的基类的对象实现的基类,所以我们对基类的访问等都是通过基类的那个对象来实现的。
另外,继承最重要的是虚函数,将才下一节实现多态的地方来讲。