[C]虚函数、虚函数表、非虚函数

虚函数、虚函数表

使用结构体表示对象,状态通过属性表示,行为通过函数指针表示。

如果对象的行为都一致,每个对象都会初始化它的函数指针,这样会导致内存浪费。

看下面这个例子:

 1 typedef struct Foo {
 2     int count;   
 3     void (* const func0)(struct Foo *pThis);
 4     void (* const func1)(struct Foo *pThis);
 5     void (* const func2)(struct Foo *pThis);
 6 } Foo;
 7 // 根据对象定义生成几个对象
 8 Foo foo0 = {0, func0_impl, func1_impl, func2_impl};
 9 Foo foo1 = {1, func0_impl, func1_impl, func2_impl};
10 Foo foo2 = {2, func0_impl, func1_impl, func2_impl};

出现以下情况会导致浪费内存

  • 有多个对象都具有相同的行为
  • 有较多的函数指针
  • 需要生成较多数量的对象

虚函数:通过函数指针实现,根据对象初始化不同而展现不同功能。

虚函数表:虚函数的集合,如下所示:

typedef struct FooVtbl {
    void (* const func0)(struct Foo *pThis);
    void (* const func1)(struct Foo *pThis);
    void (* const func2)(struct Foo *pThis);
} FooVtbl;

typedef struct Foo {
    const int count;
    const FooVtbl * const pVtbl;
} Foo;

int main()
{
    static FooVtbl foo_vtbl = {func0_impl, func1_impl, func2_impl};

    Foo foo0 = {0, &foo_vtbl};
    Foo foo1 = {1, &foo_vtbl};
    Foo foo2 = {2, &foo_vtbl};

    foo0.pVtbl->func0(&foo0);

    return EXIT_SUCCESS;
}

这就是虚函数表减少内存浪费的方式,优缺点如下:

  1. 代码结构中,仅需要对象持有指向虚函数表的指针即可,无需持有函数指针,可节约内存。
  2. 由于调用会经过虚函数表,程序的结构变复杂了。

 非虚函数

对象内持有的函数指针为虚函数,它可以根据对象的不同而使其行为发生变化。但如果函数在不同对象中的行为是相同的,对象中就无需持有函数指针了。例如

typedef struct FooVtbl {
    void (* const func0)(struct Foo *pThis);
    void (* const func1)(struct Foo *pThis);
    void (* const func2)(struct Foo *pThis);
} FooVtbl;

typedef struct Foo {
    const int count;
    FooVtbl *pVtbl;
    void (*reset_counter)(struct Foo *pThis);
} Foo;

优点

  1. 节省内存。

缺点

  1. 无法根据对象动态的改变其行为。
  2. 命名空间问题。

建议:优先使用函数指针,只有在内存有限、对象行为不会变化的情况下等,才考虑使用非虚函数。

原文地址:https://www.cnblogs.com/yanxin880526/p/15087640.html