C实现面向对象和多文件封装
提示:包含多个模块,逐步累加提升
0 基础知识的补充
1.结构体声明和定义
结构体声明:
typedef struct Girl
{
int age;//年龄
string name;//姓名
}Girl;
结构体定义:给结构体分配空间
二种方式:
第一种:Girl xiaoyue; 系统自动分配 小月就是Girl类型结构体对象
第二种:(Girl*) xiaoyue = (Girl*)malloc(sizeof(Girl)) 小月指向结构体空间
结构体是模版,用结构体定义的结构体实体或者结构体指针指向的空间实体才是实体对象,这些对象中保存各自实体的成员变量。
类似如类和对象,类是声明,类的实例化为对象。
为了方便理解,后面把结构体实例化的实体叫做对象。
1.面向对象基本实现 结构体
实现结构体,和结构体创建、释放和操作的函数。
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <assert.h>
//#define NULL ((void *)(0));
typedef char string[20];
typedef struct Girl Girl;
typedef struct Girl
{
int age;//年龄
string name;//姓名
};
//结构体操作的接口
Girl* createGirl();
Girl* createGirlwithArg(int age,const string name);
void girl_print(Girl *this);
void girl_say(Girl *this);
void girl_destroy(Girl *this);
int main()
{
/方法1/
Girl* emptyGirl = createGirl();
Girl *yue = createGirlwithArg(25, "yueyue");
girl_print(yue);
girl_say(yue);
return 0;
}
Girl *createGirl()
{
Girl *girl = (Girl *)malloc(sizeof(Girl));
assert(girl != NULL);
if(!girl)
return NULL;
//给对象中函数指针赋值,指向函数
girl->print = girl_print;
girl->say = girl_say;
girl->destroy = girl_destroy;
return girl;
}
Girl *createGirlwithArg(int age, const string name)
{
Girl *girl = createGirl();
if(!girl)
return NULL;
girl->age = age;
strcpy(girl->name, name);
return girl;
}
void girl_print(Girl *this)
{
printf("name:%s\n", this->name);
printf("age:%d\n", this->age);
}
void girl_say(Girl *this)
{
printf("my name is %s,my age is %d\n", this->name, this->age);
}
void girl_destroy(Girl *this)
{
free(this);
}
2.封装成员函数
有没有办法将与该结构体(类)相关的接口函数封装到结构体内部呢?我们知道C语言中结构体只能存放变量,无法存放函数,------>>>我们可以把 函数指针放在结构体中,在创建结构体(也就是在初始化结构体)时,让函数指针指向对应的函数即可。
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <assert.h>
//#define NULL ((void *)(0));
typedef char string[20];
typedef struct Girl Girl;
typedef struct Girl
{
int age;//年龄
string name;//姓名
//行为函数指针,指向函数
void (*destroy)(Girl *this);
void (*print)(Girl *this);
void (*say)(Girl *this);
};
Girl* createGirl();
Girl* createGirlwithArg(int age,const string name);
void girl_print(Girl *this);
void girl_say(Girl *this);
void girl_destroy(Girl *this);
int main()
{
/方法1/
Girl* emptyGirl = createGirl();
Girl *yue = createGirlwithArg(25, "yueyue");
girl_print(yue);
girl_say(yue);
//方法2/
//通过结构体中的函数指针调用函数
//yue->print为函数指针;
yue->print(yue);
yue->say(yue);
return 0;
}
Girl *createGirl()
{
Girl *girl = (Girl *)malloc(sizeof(Girl));
assert(girl != NULL);
if(!girl)
return NULL;
//给对象中函数指针赋值,指向对应的函数
girl->print = girl_print;
girl->say = girl_say;
girl->destroy = girl_destroy;
return girl;
}
Girl *createGirlwithArg(int age, const string name)
{
Girl *girl = createGirl();
if(!girl)
return NULL;
girl->age = age;
strcpy(girl->name, name);
return girl;
}
void girl_print(Girl *this)
{
printf("name:%s\n", this->name);
printf("age:%d\n", this->age);
}
void girl_say(Girl *this)
{
printf("my name is %s,my age is %d\n", this->name, this->age);
}
void girl_destroy(Girl *this)
{
free(this);
}
3.隐藏this指针
yue->print(yue); 要传2个对象,有没有办法传一次对象。
this指针指向调用的对象,即有没有办法隐藏this指针呢?
将对象指针赋值给一个全局变量this,其他函数直接使用这个this,而无需传参
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <assert.h>
typedef char string[20];
typedef struct Girl Girl;
typedef struct Girl
{
int age;//年龄
string name;//姓名
//行为函数指针,指向函数
void (*destroy)();
void (*print)();
void (*say)();
};
Girl* createGirl();
Girl* createGirlwithArg(int age,const string name);
void girl_print();
void girl_say();
void girl_destroy();
///
Girl *this = NULL; // 全局this指针,指向当前操作的对象
///
int main()
{
/方法1/
Girl* emptyGirl = createGirl();
Girl *yue = createGirlwithArg(25, "yueyue");
//先his = yue,然后在girl_print();
//方法2/
//通过结构体中的函数指针调用函数
//yue->print为函数指针;
yue->print();
yue->say();
Girl *xiao = createGirlwithArg(18, "xiaoyue");
xiao->print();
xiao->say();
(this = yue)->print();
(this = xiao)->print();
return 0;
}
Girl *createGirl()
{
Girl *girl = (Girl *)malloc(sizeof(Girl));
assert(girl != NULL);
if(!girl)
return NULL;
//给对象中函数指针赋值,指向函数
girl->print = girl_print;
girl->say = girl_say;
girl->destroy = girl_destroy;
this = girl;
return girl;
}
Girl *createGirlwithArg(int age, const string name)
{
Girl *girl = createGirl();
if(!girl)
return NULL;
girl->age = age;
strcpy(girl->name, name);
return girl;
}
void girl_print()
{
printf("name:%s\n", this->name);
printf("age:%d\n", this->age);
}
void girl_say()
{
printf("my name is %s,my age is %d\n", this->name, this->age);
}
void girl_destroy()
{
free(this);
}
4.隐藏成员变量
怎么隐藏呢?结构体嵌套,将结构体中成员变量单独存放在另一个结构体中,
typedef char string[20];
//定义私有成员变量
typedef struct GirlPrivate
{
int age;//年龄
string name;//姓名
}GirlPrivate;
typedef struct Girl Girl;
typedef struct Girl
{
void *inner;//指向私有成员变量
//成员函数接口
void (*destroy)();
void (*print)();
void (*say)();
int (*getAge)();
void (*setAge)(int age);
const char* (*getName)();
void (*setName)(const char* name);
};
Girl xiaoyue;
xiaoyue->age 就无法直接调用了 感觉比较鸡肋(哈哈,配合多文件管理更好)
xiayue->inner->age 才可以 感觉就是套了一层结构体。
具体实现:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <assert.h>
//#define NULL ((void *)(0));
typedef char string[20];
//定义私有成员变量
typedef struct GirlPrivate
{
int age;//年龄
string name;//姓名
}GirlPrivate;
// char p[10] p的类型是 char[10]
//就可以typedef char p[10]; p的类型是 char[10]
// typedef char[20] string; string类型为 字符数组,长度为20
typedef struct Girl Girl;
typedef struct Girl
{
void *inner;//指向私有成员变量
//成员函数接口
void (*destroy)();
void (*print)();
void (*say)();
int (*getAge)();
void (*setAge)(int age);
const char* (*getName)();
void (*setName)(const char* name);
};
///
Girl* this = NULL;//全局this指针,指向当前操作的对象
///
Girl* createGirl();
Girl* createGirlwithArg(int age,const string name);
void girl_print();
void girl_say();
void girl_destroy();
//成员变量接口
int girl_getAge();
void girl_setAge(int age);
const char* girl_getName();
void girl_setName(const char* name);
int main()
{
/方法1/
Girl* emptyGirl = createGirl();
//girl_print(yue);
//girl_say(yue);
//方法2/
//通过结构体中的函数指针调用函数
//yue->print为函数指针;
Girl *yue = createGirlwithArg(25, "yueyue");
yue->print(); // 传2次yue,重复传参
yue->say();
Girl *zhou = createGirlwithArg(18, "xiaoyue");
zhou->print();
zhou->say();
//yue对象里面保存着单独成员变量,this只是把yue的值变成全局,这样就可以直接调用函数了
//可以实现多个对象单独保存 指针的拷贝属于浅拷贝,还是指向同一份空间,修改一个另一个也会变
(this= yue)->print();
(this=zhou)->print();
//zhou->age;//通过对象访问成员变量,不安全,通过接口实现获取成员变量
(this = zhou)->getAge();//通过接口访问成员变量,更安全
(this = zhou)->setAge(20);
(this = zhou)->getName();
(this = zhou)->setName("zhouzhou");
return 0;
}
Girl *createGirl()
{
Girl *girl = (Girl *)malloc(sizeof(Girl));//创建Girl结构体对象
assert(girl != NULL);
if(!girl)
return NULL;
girl->inner = malloc(sizeof(GirlPrivate));//创建私有结构体对象
assert(girl->inner != NULL);
//给对象中函数指针赋值,指向函数
girl->print = girl_print;
girl->say = girl_say;
girl->destroy = girl_destroy;
girl->getAge = girl_getAge;
girl->setAge = girl_setAge;
girl->getName = girl_getName;
girl->setName = girl_setName;
//
this = girl; // 将this指针指向当前对象,放在哪里都行,只是这里更方便
//
return girl;
}
Girl *createGirlwithArg(int age, const string name)
{
Girl *girl = createGirl();
if(!girl)
return NULL;
GirlPrivate *gp = girl->inner ;
gp->age = age;
strcpy(gp->name, name);
return girl;
}
void girl_print()
{
GirlPrivate *gp = this->inner;
printf("name:%s\n", gp->name);
printf("age:%d\n", gp->age);
}
void girl_say()
{
GirlPrivate *gp = this->inner;
printf("my name is %s,my age is %d\n", gp->name, gp->age);
}
void girl_destroy()
{
free(this->inner);
free(this);
this = NULL;
this->inner = NULL;
}
int girl_getAge()
{
GirlPrivate *gp = this->inner;
return gp->age;
}
void girl_setAge(int age)
{
GirlPrivate *gp = this->inner;
gp->age = age;
}
const char *girl_getName()
{
GirlPrivate *gp = this->inner;
return gp->name;
}
void girl_setName(const char *name)
{
GirlPrivate *gp = this->inner;
strcpy(gp->name, name);
}
5.多文件封装
1.预处理阶段,会将每个.c文件中include的头文件展开.
- 每个.c文件之间是独立的,没有声明,则无法使用其他文件的变量、结构体或者函数的,要想使用其他.c的文件中的东西,需要先声明,然后才能使用。
- 声明:
变量的声明:extern a;
函数的声明:int Add(int x,int y);
结构体的声明:typedef struct girl
{
int ge;
char name[20];
}
4.函数的声明和extern来使得变量和函数,可以跨越.c文件来使用,那结构体的跨越有什么实现方式吗?答,结构体只能通过将其放在.h文件,通过.c文件包含来实现跨越,没有直接的方法。
Girl.h 其中保存着 需要对其他.c文件开放的变量,结构体和函数的声明
#pragma once
// #define NULL ((void *)(0));
typedef char string[20]; //string类型需要对其他文件开放
// 定义私有成员变量
// char p[10] p的类型是 char[10]
// 就可以typedef char p[10]; p的类型是 char[10]
// typedef char[20] string; string类型为 字符数组,长度为20
typedef struct Girl Girl;//Girl结构体需要对外开放
typedef struct Girl
{
void* inner; // 指向私有成员变量
// 成员函数接口
void (*destroy)();
void (*print)();
void (*say)();
int (*getAge)();
void (*setAge)(int age);
const char* (*getName)();
void (*setName)(const char* name);
};
Girl* createGirl();//这些接口需要对外开放
Girl* createGirlwithArg(int age, const string name);
void girl_print();
void girl_say();
void girl_destroy();
// 成员变量接口
int girl_getAge();
void girl_setAge(int age);
const char* girl_getName();
void girl_setName(const char* name);
Girl.c 其中保存着 限制的变量、函数和结构体,这些东西被限制在自己的.c文件中,
其他.文件不提前声明,是无法使用的。在.c文件中的所有东西天然与其他.c文件独立,.c文件自带封装特性。
(1) 函数实现的封装:一般来我们只想对外提供接口,而不告别人具体实现方法,
要实现其他.c文件也可以使用这些接口,还需要在.c文件中提前声明。
提前声明的常用方法:1.直接声明 2.把声明放在头文件中,inlcude头文件
(2)变量的封装,如果想对外开放,可以直接在其他.c文件或者自己的头文件中加入extern 变量的方式;不想对外开放可以在.h文件中不加extern·a,甚至可以加上static来限制;
(3)结构体的封装:在.c中的结构体,其他.c文件无法访问,要想访问,只能把结构体放在头文件中。因为结构体没有像函数声明和变量extern这种跨越.c文件的这种手段
#define _CRT_SECURE_NO_WARNINGS
#include "Girl.h"
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <assert.h>
///
Girl* this = NULL; // 全局this指针,指向当前操作的对象//变量的封装:main.c文件需要提前声明才能使用,否则也无法使用
///
typedef struct GirlPrivate //结构体的封装:mian.c文件中无法使用此类
{
int age; // 年龄
string name; // 姓名
} GirlPrivate;
#define get_Private(object) ((GirlPrivate*)(object->inner))
Girl* createGirl() //函数的封装:main.c文件需要提前声明才能使用,否则无法使用
{
Girl* girl = (Girl*)malloc(sizeof(Girl));
assert(girl != NULL);
if (!girl)
return NULL;
girl->inner = malloc(sizeof(GirlPrivate));
assert(girl->inner != NULL);
// 给对象中函数指针赋值,指向函数
girl->print = girl_print;
girl->say = girl_say;
girl->destroy = girl_destroy;
girl->getAge = girl_getAge;
girl->setAge = girl_setAge;
girl->getName = girl_getName;
girl->setName = girl_setName;
//
this = girl; // 将this指针指向当前对象,放在哪里都行,只是这里更方便
//
return girl;
}
Girl* createGirlwithArg(int age, const string name)
{
Girl* girl = createGirl();
if (!girl)
return NULL;
GirlPrivate* gp = girl->inner;
gp->age = age;
strcpy(gp->name, name);
return girl;
}
void girl_print()
{
//GirlPrivate* gp = this->inner;
// printf("name:%s\n", gp->name);
//printf("age:%d\n", gp->age);
printf("name:%s\n", get_Private(this)->name);
printf("name:%s\n", get_Private(this)->age);
}
void girl_say()
{
//GirlPrivate* gp = this->inner;
printf("my name is %s,my age is %d\n", get_Private(this)->name, get_Private(this)->age);
}
void girl_destroy()
{
free(this->inner);
free(this);
this = NULL;
this->inner = NULL;
}
int girl_getAge()
{
// GirlPrivate* gp = this->inner;
return get_Private(this)->age;
}
void girl_setAge(int age)
{
//GirlPrivate* gp = this->inner;
get_Private(this)->age = age;
}
const char* girl_getName()
{
GirlPrivate* gp = this->inner;
return get_Private(this)->name;
}
void girl_setName(const char* name)
{
strcpy(get_Private(this)->name, name);
}
main.c
#include <stdio.h>
#include "Girl.h"
int main()
{
Girl* yue = createGirl();
yue->setAge(18);
yue->setName("yueyue");
yue->print();
//无法使用GirlPrivate结构体,因为它在Girl.c文件中封装了
//GirlPrivate* pp = yue->inner;
//pp->age = 88;
yue->print();
}