c语⾔结构体this指针,c语⾔结构体模拟c++对象的⽅法,并实
现this指针
先说⼀下结构体模拟对象的基本思路。
1. 在结构体⾥定义好函数指针。
2. 在结构体外⾯定义好对象的⽅法。
3. 在结构体初始化的时候把这些⽅法的地址赋值给对应的函数指针。
4. 通过函数指针调⽤函数,并把结构体⾃⾝的地址传给函数。
这个思路容易想到,但不是很完美。毕竟定义函数的时候必须多写⼀个参数指向结构体(即this指针必须通过参数显式传递),不⽅便。调⽤的时候也要多写⼀次对象的名字:hod(&obj,arg1,arg2,…)。
于是就有了⼀个改进的思路:this指针不通过参数传递,⽽是调⽤⽅法的时候临时放到⼀个全局变量⾥,到⽅法⾥⾯再取出来。并且可以借助宏来尽可能封装,简化这⼀过程。
先来看⼀下这个头⽂件:
/*jscobj.h*/
#ifndef JSCOBJ_H
#define JSCOBJ_H
#define this m(self)
#define m(pInst) ((pInst)->_method_(pInst))
#define Define_Method(T) T * T##$Method(T *ps){_obj_arg_ = ps;return ps;}
#define Define_Member(T) struct T * (* _method_)(struct T * ps);
#define Declare_Method(T) T * T##$Method(T * ps);
#define Register_Method(pInst,T) pInst->_method_ = T##$Method;
#define MethodOf(T) T * self = (T *)_obj_arg_;
extern void *_obj_arg_;
#endif
/*jscobj.c*/
#include "jscobj.h"
void *_obj_arg_;
这⾥定义了七个宏⼀个全局变量。下⾯先来看具体的⽤法。
这⾥定义了⼀个Student类做例⼦
/*student.h*/
#ifndef _STUDENT_H_
#define _STUDENT_H_
#include
#include
#include"jscobj.h"
typedef struct Student
{
/****/Define_Member(Student)/****/
void (*printInfo)();
int (*getAge)();
int age;
char name[10];
}Student,*pStudent;
/****/Declare_Method(Student)/****/
int Student$getAge();
void Student$printInfo();
pStudent Student$$new(char *name,int age);
void Student$$Ini(pStudent stu, char *name, int age); #endif
/*student.c*/
#include "student.h"
#include "string.h"
/****/Define_Method(Student)/****/
pStudent Student$$new(char *name, int age)
{
pStudent stu = (pStudent)malloc(sizeof(Student)); Student$$Ini(stu,name,age);
return stu;
}
void Student$$Ini(pStudent stu,char *name, int age) {
/****/Register_Method(stu,Student)/****/
stu->getAge = Student$getAge;
stu->printInfo = Student$printInfo;
stu->age = age;
strcpy(stu->name,name);
}
int Student$getAge()
{
/****/MethodOf(Student);/****/
return self->age;
}
void Student$printInfo()
{
/****/MethodOf(Student);/****/
printf("name: %s, age: %d\n",this->name,this->getAge());
c语言struct用法例子}
如上,⽤到宏的地⽅着重标了⼀下。这些宏看起来就和注释差不多,但是实际上做了什么呢?
⾸先,Define_Member实际上在结构体⾥⾯定义了⼀个函数指针 _member_ ,然后Declare_Method 和 Define_Method 定义了⼀个函数,这个函数的作⽤就是把对象地址放到全局变量⾥⾯去。最后通过Register_Method把这个函数注册到_member_ 指针上,这样等于结构体多了⼀个隐藏的⽅法。
然后,来看下实际是怎么样调⽤⽅法的:
/*main.c*/
#include
#include
#include"student.h"
int main()
{
Student *stu = Student$$new("Jack",20);
m(stu)->printInfo();
system("pause");
return 0;
}
/
*输出:*/
name: Jack, age: 20
m(stu)->printInfo() 这⾥,展开m这个宏以后变成 ((stu)-> _method_(stu))->printInfo(); 也就是先⽤_method_把stu的地址放到全局变量以后再调⽤⽅法。接着在⽅法⾥⾯,第⼀⾏MethodOf(Student)把这个地址取出,并转化成⼀个Student指针,名字是self。这样,被调⽤的⽅法就知道是哪个对象调⽤它了。
最后,在⽅法⾥⾯,因为知道对象⾃⼰的地址就储存在self⾥⾯,那么通过self调⽤其他⽅法的时候就没必要再m(self),⽽可以通过另⼀个词this来替换掉m(self)。这样在⽅法内部,可以直接做到像this->getAge()这样的调⽤。这样this指针就通过宏实现了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论