C深⼊理解如何在C语⾔中实现C++的Class呢?
有些地⽅是不适合使⽤C++语⾔的。⽐如C++的虚函数,垃圾回收,异常,在底层开发中使⽤,反⽽会造成很多不必要的⿇烦。⽐如
C++编译器为了重载函数,其编译出来的函数名会被改成包括参数的形式(换名),⽽且每个编译器都有⾃⼰的内部前缀和后缀,这⼀点尤其在操作系统编写中会造成⿇烦,因为操作系统的系统调⽤使⽤汇编,⽐如中断的实现中,就需要调⽤汇编中断服务,然后在其中回调操作系统内核的C函数,如果使⽤C++函数,就不能正确指定回调函数名。
那么如何使⽤C语⾔来实现C++的类?
C语⾔中可以和class类⽐的类型就是struct了,另外还有union, 但union并不具备class的条件。
(union(共⽤体)——完全就是共⽤⼀个内存⾸地址,并且各种变量名都可以同时使⽤,操作也是共同⽣效。内存的⼤⼩与成员中长度的最⼤的决定;)
如何使⽤C语⾔才能让struct实现class呢?
C语⾔⽀持函数指针的定义,并且struct中也⽀持函数指针定义。
int func(int a, int b);
定义函数指针:
int (*pfunc)(int, int);
当定义pfunc = func时,下⾯两个调⽤是⼀样的:
func(10, 20);
pfunc(10, 20);
将函数指针定义到struct中:
#include<stdio.h>
typedef struct A
{
int data;
int (*Val)(int a);
}A;
int Val(int a)
wrc坐垫
{
return a;
}
int main()
{
A a;
a.Val = Val;
printf("%d",a.Val(10)); //输出:10
福建车市
}
这样可以得到10的结果。
我们知道class中隐含了⼀个this指针,那在Val函数中怎样才能得到this呢?
对了,就通过参数传递:
#include<stdio.h>
typedef struct A A;
struct A
{
int data;
int (*Val)(A* that, int a);
};
int Val(A* that, int a)
{
return that->data + a;
}
int main()
{
A a;
a.data=8;
a.Val = Val;
printf("%d",a.Val(&a, 10));  //输出:18
}
使⽤that来代替this,这样如果这段代码拿到C++编译器下⾯时也不会跟struct中隐含的this冲突。这样就定义了struct来代替class,唯⼀的缺点是定义好以后,每次调⽤函数需要将对象指针传递进去,这也是⽆可避免的。
进阶1:构造函数
上⼀步中,a.Val = Val;写在外⾯,如果有好⼏个成员(函数),就会很⿇烦,每⼀个对象的赋值都要重复相似操作。这时就需要定义⼀个构造函数。
#include<stdio.h>
typedef struct A A;
struct A
{
int data;
int (*Val)(A* that,int a);
};
int Val(A* that,int a)
{
return that->data + a;
}
A* _A(A* that, int data)
{
that->data = data;
that->Val = Val;
理念s1return that;
}
int main()
{
A a;
_A(&a, 20);
printf("%d",a.Val(&a, 10));
}
这样定义⼀个对象并赋值就只需要两⾏代码。卡尔森
注意:这⾥构造函数只能是⼀个普通函数,不能作为成员(函数),因为构造函数只调⽤⼀次,没有作为成员的必要,并且构造函数,如果是成员也没法在构造前知道构造函数是什么,因此只能在外部指定。
进阶2:继承
实现继承才是使⽤类的终极⽬标。
这⾥先暂时、⽽且也没法实现虚函数之类的,不⽤考虑这些。
实现继承需要⽤到上⾯提到的union
#include<stdio.h>
typedef struct A A;
struct A
{
int data;
int (*Val)(A* that,int a);
};
int Val(A* that,int a)
{
return that->data + a;
}
A* _A(A* that, int data)
{
that->data = data;
that->Val = Val;
return that;
}
typedef struct B B;
struct B
{
union
{
A super;
struct
{
int data;
int (*Val)(A* that, int a);
};
};
int val;
};
B* _B(B* that, int val)
{
_A(&that->super,val);
that->val = val;
}
int main()
{
B b;
_B(&b, 30);
printf("%d\n",b.Val(&b.super, 20));
}
在union中,定义了基类A,以及将基类A中的成员都拷贝到了⼀个匿名struct中。在C规范中,union的匿名struct后⾯定义⼀个变量名,那么使⽤变量名.成员才能得到变量,⽽如果没有变量名,则直接使⽤成员名就能得到变量,如下:
union
{
float f[2];
struct
{
float f1;
float f2;
}uf;
小鹏汽车回应高架撞人}um;
要得到f[1],使⽤um.fu.f2可以得到。
union
{
float f[2];
struct
{
float f1;
float f2;
起亚k5按揭
};
}um;
只使⽤um.f2就能得到f[1]。
利⽤这点,可以让基类的成员变成继承类的成员。继承类中super部分是基类,⽽⾃⾝⼜定义了val这个成员变量,是属于基类以外的,⽽且更有意思的是,在B的构造函数中,可以直接通过that->super来构造a,并且构造函数完了以后,b.data和b.Val就是构造A以后的成员,它们分别等于b.super.data和b.super.Val。