• operator=() 重载的问题


    最近在重构GUI 显示输出相关代码的时候,引入了一个GfxSender的类来管理。先大概说一下这个类是干什么的,以及为什么有这个需求。好吧,本质是同一件事情。就是以往gui渲染好了之后,会直接把渲染结果送给合成器,由合成器负责画面的最终输出。

    现在事情变得有些复杂了,有个项目说,需要把GUI渲染好的结果share给一个别的模块,在哪里做统一的画面畸变校正,还要支持热切换。还有一个项目需要把GUI渲染好的画面通过wayland client 给weston合成。这么一来,看起来我们需要的是一个中间层GfxSender, 在这里负责把拿到的帧到底往哪里send. 我不由得脑洞打开,搞不好哪天还要支持GUI画面的编码存储等,这些都不是不可能.  以及为了应对一些没有屏幕的测试GUI框架的需求,这里是不是要搞个VirtualSender,支持将GUI存储成BMP文件.

    于是我就开始了我的重构,首先是父类GfxSender,  然后是派生类CompositorClientSender,MdcClientSender, VirtualSender等。

    在动手实现之前,先把测试代码写好,这样,方便我们去思考到底需要设计哪些接口,我的测试代码大致如下:

    int main() {
    
    GfxSender* base_sender = nullptr;
    VirtualGfxSender * virtual_sender = new VirtualGfxSender (); 
    MdcClientSender * mdc_sender = new MdcClientSender ();
    
    base_sender = virtual_sender;
    base_sender->sendFrame(fb);
    
    base_sender = mdc_sender;
    base_sender->sendFrame(fb);
    
    delete virtual_sender;
    delete mdc_sender;
    
    return 0;
    }

    但是sender之间切换不是仅仅简简单单,一个赋值就能解决的事情,在从virtual_sender 切换到mdc_sender之前,需要调用一个reclaimFrame函数,该函数将会被设计成一个同步的调用,用来回收client通过这个sender 发送出去的buffer. 但是如果每次都在 = 之前干这个事情,看起来不够简洁,所以我的想法就是,重载operator=(), 在=里面做reclaim的事情,这样就好看了。

    于是我的想法是这样的:

    class GfxSender {
    public:
      virtual void reclaimFrame(void);
    virtual void sendFrame(void* fb);
    virtual GfxSender* operator=(GfxSender* sender) {
         cout << "xxx" << endl;
    if(typeid(*sender) != typeid(GfxSender*)) { reclaimFrame(); } return sender; } };

    实时证明,我还是不太了解运算符的重载。我在测试的时候,发现base_sender在执行= 后,压根就没有变化。甚至连打印都走不进去。后来经过滕老师指点 *base_sender = mdc_sender; 才能走进重载的operator=()函数中

    此时,我才恍然大悟,运算符重载只对类对象生效,对类的指针压根不会走到operator=()中去,这也是为什强行base_sender->operator=(mdc_sender)可以worker, 但是base_sender = mdc_sender不能work. 另外,即使*base_sender = mdc_sender可以执行,但是执行完后,base_sender还是原来的值,压根不会改变。因为*base_sender = mdc_sender; 被编译器翻译成:

    GfxSender* operator=(this, mdc_sender);

    执行完之后只是返回了mdc_sender, base_sender压根没变,所以为了base_sender能改变,就比较丑陋了,需要这么用

    base_sender = *base_sender = mdc_sender;
    //或者
    //base_sender = base_sender->operator=(mdc_sender);

    简直让人无法直视好吧,这么写代码,将会非常难以维护。我觉得这样不行,后来,我想到一个好办法,既然运算符重载是针对类的,那我干脆把GfxSender* 封装到一个wrapper类里面去,这样不就可以了吗:

    class GfxSenderPtr { 
    public :
      GfxSenderPtr ( GfxSenden ptr ): m ( ptr ){;} 
      GfxSenderPtr operator =( GfxSender * ptr );
      void sendFrame ( void* fb ){ m -> sendFrame ( fb );}
    private :
      GfxSender *: nullptr ;
    
    GfxSenderPtr GfxSenderPtr::operator=( GfxSender * ptr )
    {
         m->reclaimFrame ();
         m =ptr;
         return m;
    }

    通过这种方式,我们就可以这样用了:

    GfxSender * base _ sender = new GfxSender ; 、
    GfxSenderPtr base _ ptr ( base _ sender );
    
    base_ptr = mdc_sender;
     
    //xxx
    
    base_ptr = virtual_sender;
  • 相关阅读:
    JQuery OOP 及 OOP思想的简易理解
    windows下编写shell脚本执行错误
    Kafka常用命令
    OffsetDateTime工具类
    windows下安装consul
    磁盘阵列方案
    shell基本语法记录
    学习CGLIB与JDK动态代理的区别
    Spring源码分析-BeanFactoryPostProcessors 应用之 PropertyPlaceholderConfigurer
    局域网内搭建git
  • 原文地址:https://www.cnblogs.com/Arnold-Zhang/p/15730183.html
Copyright © 2020-2023  润新知