您的位置:首页 > 编程语言 > C语言/C++

C++ 虚拟函数vs 回调函数 像有虚拟方法表一样有一个虚拟变量表就可以实现类级回调函数了

2012-11-25 04:26 816 查看
虚拟函数使得对象用同一个名字,调用不同函数.

这种多态实现了某种概念的抽象.

用回调也可以达到类似的效果,某种意义上,用回调更灵活.

由于C++的类回调函数的强类型导致用起来不够灵活方便,

这里的回调函数可以用Delegate代替.

其实用回调是典型的使用聚合而不使用继承的思路.

最典型的例子就是Thread类,

通常的做法是写一个非虚拟的Run,调用虚拟的Excute.

用到Thread的地方,继承Thread实现Excute即可.

而用回调的方式,只需设置回调即可,不用新建一个类来继承.

尤其当用到的Thread较多时,避免了类的数目的膨胀.

针对接口编程,经常声明一个接口类,

一方拥有这个接口,使用这个接口,另一方从这个接口继承,实现接口.

如果采用Delegate的方法,有时可以省去单独的接口类.

虚拟函数的问题在于其同时实现了接口继承和实现继承.

而回调函数可以看作接口继承,因此更灵活.

虚拟方法表由编译器自动处理,回调函数由人工管理.

但是,虚拟函数基于类,同一个类的对象共享一个虚拟方法表,

而回调函数却是基于对象的,每个对象都有一个回调函数指针.

能否让对象共享同一个回调函数指针?

类可以共享静态变量,但类和子类也共享该静态变量.

(单例模式不能继承就面临的这个问题,用模板实现编译时多态).

那么除非根据函数名结合类名查表,调用不同函数.

如果语言支持与子类独立的类级共享变量,

也就是说在父类声明一个类级变量,子类中也有一个同名的类级变量.这两个变量同名但独立.

就像虚拟方法表一样有一个虚拟变量表就好了.

这样就可以实现前面的基于类的回调函数.

语言不直接支持,我们只有diy了

//ClassVariable代表类共享变量.

//ClassVariable中主要存放的是类级回调函数,或者说Deletegate.

struct ClassVariable

{

};

//每个类都声明一个同名的静态成员变量ClassVar;

class TObject

{

static ClassVariable* ClassVar;

virtual ClassVariable* GetClassVariable(){return ClassVar};

//或者通过一个全局的hash表,由类名得到相应的ClassVar

};

每个类从父类继承并扩展相应的ClassVariable结构.

那么如何实现多态呢?

在一个非虚拟函数里,调用ClassVar所指向的一个运行时设定的Deletegate.

使用ClassVar前

借鉴QT中的RTTI的相关思路.

提供一个函数,进行类型转换,将通用的ClassVariable,

转换为与类相关的特定类型的指针.

某种意义上RTTI信息就是类的共享的数据.

可以研究下C++的Rtti,以及类库的Rtti的实现原理.

如果C++直接支持delegate,虚拟变量表,消息机制就好了

如果每一个类对应的rtti构成一个包含vmt成员的MetaClass,并且用户可以自定义继承,扩充之就好了.





(Click here for a personal note from Marshall Cline.)
C++ FAQ /

Section 31 / FAQ 31.2
Section 31:

31.1What is value and/or reference semantics, and which is best in C++?
31.2What is "virtual data," and how-can / why-would I use it in C++?
31.3What's the difference between
virtual data and dynamic data?
31.4Should I normally use pointers to freestore allocated objects
for my data members, or should I use "composition"?
31.5What are relative costs of the 3 performance hits associated
with allocating member objects from the freestore?
31.6Are "inline
virtual" member functions ever actually "inlined"?
31.7Sounds like I should never use reference semantics, right?
31.8Does the poor performance of reference semantics mean I should pass-by-value?


E-mail the author


[ Subject index | About the author | ©
]

Revised Jul 4, 2012








[31.2] What is "virtual data," and how-can / why-would I use it in C++?

virtual data allows a derived class to change the exact class of a baseclass's member object.
virtual data isn't strictly "supported" by C++,however it can be simulated in C++. It ain't pretty, but it works.

To simulate virtual data in C++, the base class must have a pointer to themember object, and the derived class must provide a
new object to bepointed to by the base class's pointer. The base class would also have oneor more normal constructors that provide their own referent (again via
new),and the base class's destructor would delete the referent.

For example, class Stack might have an Array member object (using apointer), and derived
class StretchableStack might override the baseclass member data from
Array to StretchableArray. For this to work,StretchableArray would have to inherit from
Array, so Stack would have anArray*. Stack's normal constructors would initialize this
Array* with anew Array, but Stack would also have a (possibly
protected)constructor that would accept an Array* from a derived class.StretchableStack's constructor would provide a
new StretchableArrayto this special constructor.

Pros:

Easier implementation of StretchableStack(most of the code is inherited)
Users can pass a StretchableStack as a kind-of Stack

Cons:

Adds an extra layer of indirection to access the Array
Adds some extra freestore allocation overhead(both new and delete)
Adds some extra dynamic binding overhead(reason given in next FAQ)

In other words, we succeeded at making our job easier as theimplementer of
StretchableStack, but all our users
payfor it. Unfortunately the extra overhead was imposed on both users ofStretchableStack
and on users of Stack.

Please read the rest of this section. (You will not get a balancedperspective without the others.)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐