之前看C++的标准,看到了一个词:基类子对象。结合GTK的实现,明白了继承的含义。这是 C语言实现面向对象的基础。
所以,C语言面向对象?C 语言不是面向过程的编程语言吗?
让我们看下面的代码:
#include <cstdio>
class A{
public:
A(int a):a_(a){}
int a() {
return a_;
}
private:
int a_;
};
int main() {
A *a=new A(2);
printf("%d",a->a());
delete a;
return 0;
}
和
#include <stdio.h>
#include <stdlib.h>
struct A {
int a_;
};
void init_A(struct A* a, int a_) {
a=(struct A*)malloc(sizeof(struct A));
a->a_=a_;
}
int get_a(struct A* a) {
return a->a_;
}
void delete_a(struct A* a) {
free(a);
}
int main() {
struct A* a;
init_A(a, 2);
printf("%d",get_a(a));
delete_a(a);
return 0;
}
大家可以反汇编看看这两个程序有多少相同的地方。第一个程序的A::a函数和第二个程序的get_a函数几乎是一样的。
实际上类这个东西本质上是个结构体,成员函数是独立存在的,this指针是单独传入的,public/private只存在于语法层面。通过复杂的指针运算,可以访问到被标记为private的成员。
那么这和我们说的继承有啥关系呢?参考GTK的实现,我认为继承本质上是这样的:
struct Base{
// 基类
}
struct Derived{
Base base;
// 派生类内容
}
当我们调用derived->a时,如果Derived类里没有a字段,则会查找derived->base.a。这也解释了名字遮蔽是怎么一回事。
这也解释了下面的情况:两个类Base1和Base2均被派生类Derived继承(多继承),那么(Base1)p_derived==(Base2)p_derived返回false。
虚函数表是个更复杂的东西,且待我研究研究。
