应该用bind+function取代虚函数需要实现吗吗

本文的主要思想是面向对象的”繼承“和”多态“能用就不要用因为很难纠正错误。如果有一颗类型继承树人们在一开始设计时就得考虑各个class在树上的位置。随着时間的推移和需求的更迭原来正确的继承关系到后面就会发现越来越不满足于拓展和使用,而C++本身又缺少良好的重构工具在一个偌大的項目中,如果做大范围的重构那么每个模块的测试是别不可少的,带来的时间成本和工作量是不可预估的

总之,继承和虚函数需要实現吗这条路会让你一直走到黑并且很难再寻找别的出路。在C++里我们可以使用boost::function和boost::bind取代虚函数需要实现吗。

用”继承树“这种方式来建模确实是基于概念分类的思想。”分类“确实是可以抽象的很具体但是往往这种抽象的背后会带来大量的耦合关系,因为分类的概念的維度选取往往会根据需求进行当需求发生了变化那么分类的很有可能会产生交集,导致概念的模糊比如:

生物,可以分为脊柱动物和無脊柱动物有脊柱动物又分为鱼类、两栖类、爬行类、鸟类和哺乳类。可以按这种进行分类当然如果根据需求还可以分为会飞、会走嘚、会跳的、会游的等等。

不同的人看法可能不同比如一部影片里包含很多成分,成分的比重往往因人而异那么是该归于悬疑还是归于科幻等等

在编程方面可能带来的情况会更加复杂,因为物体的概念可能会根据成分发生变化一开始分入A类可能是合理的,随着功能的演化分入B类可能会更加合适,但是这种改动可能代价太高了

现代编程语言中,Ruby的duck和Google Go的无继承都可以看做以tag来取代分类的代表一个object只偠提供相应的operations,就能当成某个东西不需要显式地继承或实现某个接口。这确实是极好的我们通过这些语言的实现方式也可以收到启发,通过函数接口的方式来拓展实现手段的多样性

在传统的C++程序中,事件回调是通过虚函数需要实现吗进行的网络库往往定义一个或者幾个抽象基类(handle class),其中声明了一些(纯虚函数需要实现吗)如onConnect()、onDisconnect()、onMessage()、onTimer()等等,使用者需要继承这些基类并覆写和引用实现,使用者必須把派生类对象的指针或者引用隐式转换为基类的指针或者引用在注册到网路库中。但是这里面就有一个问题如何管理派生类对象的生命期在这种接口风格中,MyHandler的对象的所有权和生命很模糊

boost::function可以指向任何函数。包括成员函数当用bind把某个成员函数绑定到某个对象上时,我们可以得到一个闭包例如:

如果没有boost::bind,那么boost::function就做不了任何事但是有了bind,”同一个类的不同对象可以delegate给不同的实现从而实现不同嘚行为“

程序库的设计不应该给使用者带来不必要的耦合,而继承是第二强的一种耦合(最强耦合是友元)如果一个程序库限制其使用鍺必须从某个class派生,那么这可能是一个很糟糕的设计

缺点:如果一个class的三个method需要再三个不同的线程中执行,就得写helper class

以boost::function作为桥梁NetServer class对其使鼡者没有任何类型上的限制,只对成员函数的参数和返回类型有限制使用者EchoServer也完全不知道NetServer的存在,只要在main()里把二者装配到一起程序就跑起来了。

对面向对象程序设计的影响

面向对象的三大要素封装、继承和多态封装是根本的,继承和多态则可有可无用class来表示concept, 这是根本;继承和多态其耦合性太强。

继承和多态不仅规定了函数名称参数,返回类型等等还对规定了类的继承关系。有了boost::function+boost::bind不再考虑class之間的继承关系只需要基于对象的设计。

如果是指OO中的public继承即为了接口与现实分离,那么只会在派生类的数目和功能完全确定下使用鈈为将来拓展考虑,这时候使用面向对象或许是不错的选择一旦考虑拓展那就不考虑了

进一步声明,interface的颗粒度应该足够小或者包含一個method就够了,那么interface实际上退化成了给类大的标签(tag)这里可以类比考虑golang中的interface。在这种情况下完全用boost::function来代替。比如:

//一个即能用到run也能用到fly嘚客户 //一个既能用到run,也能用到swim的客户

这是一篇比较情绪化的blog中心思想是“继承就像一条贼船,上去就下不来了”而借助boost::function和boost::bind,大多数情况下你都不用上贼船。

boost::function和boost::bind已经纳入了std::tr1这或许是C++0x最值得期待的功能,它将彻底改变C++库的设计方式以及应用程序的编写方式。

boost::function就像C#里的delegate可以指向任何函数,包括成员函数当用bind把某个成员函数绑到某个對象上时,我们得到了一个closure(闭包)例如:

如果没有boost::bind,那么boost::function就什么都不是而有了bind(),“同一个类的不同对象可以delegate给不同的实现从而实現不同的行为”(myan语),简直就无敌了

程序库的设计不应该给使用者带来不必要的限制(耦合),而继承是仅次于最强的一种耦合(最強耦合的是友元)如果一个程序库限制其使用者必须从某个class派生,那么我觉得这是一个糟糕的设计不巧的是,目前有些程序库就是这麼做的

缺点:如果一个class的三个method需要在三个不同的线程中执行,就得写helper class(es)并玩一些OO把戏

以boost::function作为桥梁,NetServer class对其使用者没有任何类型上的限制呮对成员函数的参数和返回类型有限制。使用者EchoService也完全不知道NetServer的存在只要在main()里把两者装配到一起,程序就跑起来了

// 扮演上帝的角色,紦各部件拼起来

对面向对象程序设计的影响

一直以来我对面向对象有一种厌恶感,叠床架屋绕来绕去的,一拳拳打在棉花上不解决實际问题。面向对象三要素是封装、继承和多态我认为封装是根本的,继承和多态则是可有可无用class来表示concept,这是根本的;至于继承和哆态其耦合性太强,往往不划算

继承和多态不仅规定了函数的名称、参数、返回类型,还规定了类的继承关系在现代的OO编程语言里,借助反射和attribute/annotation已经大大放宽了限制。举例来说JUnit 3.x 是用反射,找出派生类里的名字符合 void test*() 的函数来执行这里就没继承什么事,只是对函数嘚名称有部分限制(继承是全面限制一字不差)。至于JUnit 4.x 和 NUnit

我的猜测是当初提出面向对象的时候,closure还没有一个通用的实现所以它没能算作基本的抽象工具之一。现在既然closure已经这么方便了或许我们应该重新审视面向对象设计,至少不要那么滥用继承

自从找到了boost::function+boost::bind这对神兵利器,不用再考虑类直接的继承关系只需要基于对象的设计(object-based),拳拳到肉程序写起来顿时顺手了很多。

对面向对象设计模式的影响

既嘫虚函数需要实现吗能用closure代替那么很多OO设计模式,尤其是行为模式失去了存在的必要。另外既然没有继承体系,那么创建型模式似乎也没啥用了

最明显的是Strategy,不用累赘的Strategy基类和ConcreteStrategyA、ConcreteStrategyB等派生类一个boost::function<>成员就解决问题。在《设计模式》这本书提到了23个模式我认为iterator有用(戓许再加个State),其他都在摆谱拉虚架子,没啥用或许它们解决了面向对象中的常见问题,不过要是我的程序里连面向对象(指继承和哆态)都不用那似乎也不用叨扰面向对象设计模式了。

前面的EchoService可算是依赖注入的例子EchoService需要一个什么东西来发送消息,它对这个“东西”的要求只是函数原型满足SendMessageCallback而并不关系数据到底发到网络上还是发到控制台。在正常使用的时候数据应该发给网络,而在做单元测试嘚时候数据应该发给某个DataSink。

我认为这么做纯粹是脱了裤子放屁直接传入一个SendMessageCallback对象就能解决问题。在单元测试的时候可以boost::bind()到MockServer上,或某個全局函数上完全不用继承和虚函数需要实现吗,也不会影响现有的设计

如果是指OO中的public继承,即为了接口与实现分离那么我只会在派生类的数目和功能完全确定的情况下使用。换句话说不为将来的扩展考虑,这时候面向对象或许是一种不错的描述方法一旦要考虑擴展,什么办法都没用还不如把程序写简单点,将来好大改或重写

这个问题来自那个经典的讨论:不会飞的企鹅(Penguin)究竟应不应该继承自鸟(Bird),如果Bird定义了virtual function fly()的话讨论的结果是,把具体的行为提出来作为interface,比如Flyable(能飞的)Runnable(能跑的),然后让企鹅实现Runnable麻雀实现Flyable囷Runnable。(其实麻雀只能双脚跳不能跑,这里不作深究)

进一步的讨论表明,interface的粒度应足够小或许包含一个method就够了,那么interface实际上退化成叻给类型打的标签(tag)在这种情况下,完全可以使用boost::function来代替比如:

// 企鹅能游泳,也能跑
// 麻雀能飞也能跑
 
 // 装配起来,Foo要麻雀Bar要企鹅。
 

boost::weak_ptr简潔地实现了多播(multi-cast)即一对多的回调,并且考虑了对象的生命期管理与多线程安全;并且自然地,对使用者的类型不作任何限制篇幅略長,留作下一篇blog吧(boost::signals也实现了Signal/Slot,但可惜不是线程安全的)

最后,向伟大的C语言致敬!

这是一篇比较情绪化的blog中心思想是“继承就像一条贼船,上去就下不来了”而借助boost::function和boost::bind,大多数情况下你都不用上贼船。

boost::function和boost::bind已经纳入了std::tr1这或许是C++0x最值得期待的功能,它将彻底改变C++库的设计方式以及应用程序的编写方式。

如果没有boost::bind那么boost::function就什么都不是,而有了bind()“同一个类的不同对象可以delegate给不同的實现,从而实现不同的行为”(myan语)简直就无敌了。


程序库的设计不应该给使用者带来不必要的限制(耦合)而继承是仅次于最强的┅种耦合(最强耦合的是友元)。如果一个程序库限制其使用者必须从某个class派生那么我觉得这是一个糟糕的设计。不巧的是目前有些程序库就是这么做的。

缺点:如果一个class的三个method需要在三个不同的线程中执行就得写helper class(es)并玩一些OO把戏。


以boost::function作为桥梁NetServer class对其使用者没有任何类型上的限制,只对成员函数的参数和返回类型有限制使用者EchoService也完全不知道NetServer的存在, 只要在main()里把两者装配到一起程序就跑起来了。


对面姠对象程序设计的影响


一直以来我对面向对象有一种厌恶感,叠床架屋绕来绕去的,一拳拳打在棉花上不解决实际问题。面向对象彡要素是封装、继承和多态我认 为封装是根本的,继承和多态则是可有可无用class来表示concept,这是根本的;至于继承和多态其耦合性太强,往往不划算

继承和多态不仅规定了函数的名称、参数、返回类型,还规定了类的继承关系在现代的OO编程语言里,借助反射和 attribute/annotation已经夶大放宽了限制。举例来说JUnit 3.x 是用反射,找出派生类里的名字符合 void test*() 的函数来执行这里就没继承什么事,只是对函数的名称有部分限制(繼承是全面限制一字不差)。至于JUnit 4.x 和 NUnit

我的猜测是当初提出面向对象的时候,closure还没有一个通用的实现所以它没能算作基本的抽象工具の一。现在既然closure已经这么方便了或许我们应该重新审视面向对象设计,至少不要那么滥用继承

自从找到了boost::function+boost::bind这对神兵利器,不用再考虑類直接的继承关系只需要基于对象的设计(object-based),拳拳到肉程序写起来顿时顺手了很多。


对面向对象设计模式的影响


既然虚函数需要实现吗能用closure代替那么很多OO设计模式,尤其是行为模式失去了存在的必要。另外既然没有继承体系,那么创建型模式似乎也没啥用了

个State),其他都在摆谱拉虚架子,没啥用或许它们解决了面向对象中的常见问题,不过要是我的程序里连面向对象(指继承和多态)都不用那似乎也 不用叨扰面向对象设计模式了。


前面的EchoService可算是依赖注入的例子EchoService需要一个什么东西来发送消息,它对这个“东西”的要求只是函数 原型满足SendMessageCallback而并不关系数据到底发到网络上还是发到控制台。在正常使用的时候数据应该发给网络,而在做单元测试的 时候数据應该发给某个DataSink。

我认为这么做纯粹是脱了裤子放屁直接传入一个SendMessageCallback对象就能解决问题。在单元测试的时候可以boost::bind()到MockServer上,或某个全局函数上完全不用继承和虚函数需要实现吗,也不会影响现有的设计


如果是指OO中的public继承,即为了接口与实现分离那么我只会在派生类的数目囷功能完全确定的情况下使用。换句话说不为将来的扩展考虑,这时候面向对象或许是一种不错的描述方法一旦要考虑扩展,什么办法都没用还不如把程序写简单点,将来好大改或重写


这个问题来自那个经典的讨论:不会飞的企鹅(Penguin)究竟应不应该继承自鸟(Bird),洳果Bird定义了virtual function fly()的话讨论的结果是,把具体的行为提出来作为interface,比如Flyable(能飞的)Runnable(能跑的),然后让企鹅实 现Runnable麻雀实现Flyable和Runnable。(其实麻雀只能双脚跳不能跑,这里不作深究)

进一步的讨论表明,interface的粒度应足够小或许包含一个method就够了,那么interface实际上退化成了给类型打的標签(tag)在这种情况下,完全可以使用boost::function来代替比如:

使用者的类型不作任何限制,篇幅略长留作下一篇blog吧。(boost::signals也实现了Signal/Slot但可惜不是线程安全的。)

最后向伟大的C语言致敬!

我要回帖

更多关于 虚函数需要实现吗 的文章

 

随机推荐