大学生活 / 计算机相关 · 2025年10月21日 0

面向对象继承的本质

之前看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。

虚函数表是个更复杂的东西,且待我研究研究。