以boost::function和boost:bind取代虚函数
这是一篇比较情绪化的blog,中心思想是“继承就像一条贼船,上去就下不来了”,而借助boost::function和boost::bind,大多数情况下,你都不用上贼船。
boost::function和boost::bind已经纳入了std::tr1,这或许是C++0x最值得期待的功能,它将彻底改变C++库的设计方式,以及应用程序的编写方式。
Scott Meyers的Effective C++ 3rd ed.第35条款提到了以boost::function和boost:bind取代虚函数的做法,这里谈谈我自己使用的感受。
基本用途
boost::function就像C#里的delegate,可以指向任何函数,包括成员函数。当用bind把某个成员函数绑到某个对象上时,我们得到了一个closure(闭包)。例如:
class Foo
{
public:
void methodA();
void methodInt(int a);
};
class Bar
{
public:
void methodB();
};
boost::function<void()> f1; // 无参数,无返回值
Foo foo;
f1 = boost::bind(&Foo::methodA, &foo);
f1(); // 调用 foo.methodA();
Bar bar;
f1 = boost::bind(&Bar::methodB, &bar);
f1(); // 调用 bar.methodB();
f1 = boost::bind(&Foo::methodInt, &foo, 42);
f1(); // 调用 foo.methodInt(42);
boost::function<void(int)> f2; // int 参数,无返回值
f2 = boost::bind(&Foo::methodInt, &foo, _1);
f2(53); // 调用 foo.methodInt(53);
如果没有boost::bind,那么boost::function就什么都不是,而有了bind(),“同一个类的不同对象可以delegate给不同的实现,从而实现不同的行为”(myan语),简直就无敌了。
对程序库的影响
程序库的设计不应该给使用者带来不必要的限制(耦合),而继承是仅次于最强的一种耦合(最强耦合的是友元)。如果一个程序库限制其使用者必须从某个class派生,那么我觉得这是一个糟糕的设计。不巧的是,目前有些程序库就是这么做的。
例1:线程库
常规OO设计:
写一个Thread base class,含有(纯)虚函数 Thread#run(),然后应用程序派生一个继承class,覆写run()。程序里的每一种线程对应一个Thread的派生类。例如Java的Thread可以这么用。
缺点:如果一个class的三个method需要在三个不同的线程中执行,就得写helper class(es)并玩一些OO把戏。

本文探讨了如何使用boost::function和boost::bind来替代虚函数,减少继承带来的耦合。作者指出,这两个工具可以实现闭包,改变C++库和应用程序的编写方式。通过示例展示了它们在线程库和网络库设计中的应用,并讨论了对面向对象设计模式的影响,尤其是在简化Strategy模式和依赖注入方面的优势。文章强调,只有在功能和派生类完全确定的情况下,才应考虑使用继承。最后,作者提出使用接口应足够细化,并介绍了如何用boost::function实现类似接口的功能。
最低0.47元/天 解锁文章
1991





