zoukankan      html  css  js  c++  java
  • [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. 命名空间问题。

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

  • 相关阅读:
    npm version patch
    nginx 操作
    基于 Vue CLI 组件库封装,按需加载实现
    nginx 配置文件路径获取
    Laravel 生产资源路由并指定模型
    base.js,通用js方法,Js方法封装
    jquery.params.js,Jquery获取页面参数,js获取页面参数
    layui使用,LayUI select不显示,LayUI文件上传,Layui自定义校验规则
    Layer弹窗消息封装,Layer消息提示封装,Layer使用
    Html跨域js封装,前端页面跨域js,postMessage实现跨域
  • 原文地址:https://www.cnblogs.com/yanxin880526/p/15087640.html
Copyright © 2011-2022 走看看