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;