• B.S 举的一个结合Generic和OO两种设计思维的经典例子(CC) - [C++]

    2006-12-05

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://morningsun.blogbus.com/logs/3973238.html

    Bjarne: 如果你面对的问题既需要某些RTTI功能(需要面向对象编程),又具有一些能够从编译期决议中获益的方面(泛型编程的用武之地)的话,那么你就需要将面向对象编程和泛型编程结合起来。

    将一个保存了shape的容器中的所有元素都显示出来就属于这类问题。考虑以下代码:

    void draw_all(vector<Shape*>& vs)
    {
        for (int i=0; i<vs.size(); ++i) vs[i]->draw();

    我猜想这并不能被看作纯粹的面向对象编程,因为我直接利用了“vs是一个装有Shape*元素的vector”这个事实。毕竟,类型的参数化通常是被认为属于泛型编程的范畴。我们也可以消除这种对静态类型信息的使用(所谓“不纯粹的面向对象编程”): 

    void draw_all(Object* container)
    {
        Vector* v = dynamic_cast<Vector*>(container);
        for (int i=0; i<v.size(); ++i)
        {
            Shape* ps = dynamic_cast<Shape*>(v[i]);
            ps->draw();
        }

    但凡鼓励以上这种风格的语言,其语法通常都比较漂亮,然而这个例子却说明了当你把静态类型信息的使用减至最小的时候发生了什么。如今,在C++或其它语言中,仍然有人在使用这种风格。我只是希望他们在错误处理方面有系统化的准备。 

    在前一个例子中,vector<Shap*>依赖于对泛型编程的一个最简单的运用:vector的元素类型被参数化了,而且我们的示例代码正获益于此。在这个方向上我们还可以走得更远,即推而广之到所有标准库容器身上: 

    template<class Container> void draw_all(Container& cs)
    {
        for (typename C::iterator p=cs.begin(); p!=cs.end(); ++p)
            (*p)->draw();

    例如,这段代码就既可以作用于vector上,又可以作用于list上。编译期决议确保我们不用为这种泛化处理付出任何运行期额外代价。我们还可以通过在draw_all()的使用接口中运用迭代器,从而进行进一步的泛化处理: 

    template<class Iter> void draw_all(Iter fist, Iter last)
    {
        for (; first!=last; ++first)
            (*first)->draw();

    这就使内建数组类型都得到了支持: 

    Shape* a[max];
    //
    a中填充Shape*类型的元素
    draw_all(a,a+max); 

    我们还可以结合运用标准库算法for_each()和函数适配器mem_fun()来消除显式的循环: 

    template<class Iter> void draw_all(Iter fist, Iter last)
    {
        for_each(first, last, mem_fun(&Shape::draw);

    注意,这也是一个关于编译错误信息变得可怕的例子,因为我们并没有显式地表达出我们的假设。例如,我们假设容器里的元素类型为Shape*,然而在代码中,这个假设却相当隐晦。这种情况下我们可以使用约束类(此处为Point_to): 

    template<class Iter> void draw_all(Iter fist, Iter last)
    {
        Points_to<Iter,Shape*>();
        for_each(first, last, mem_fun(&Shape::draw);

    然而我们又确实很想说明“firstlast必须为前向迭代器”: 

    template<Forward_iterator<Shape*> Iter>
    void draw_all(Iter fist, Iter last)
    {
        for_each(first, last, mem_fun(&Shape::draw);

    这是“concepts”可以大展拳脚的地方之一。 


    历史上的今天:

    cat功能 2007-12-05

    收藏到:Del.icio.us




    评论

  • 您好,可以向您请教下,OMNET的使用问题吗?
    morningSun回复彭宇说:
    不好意思,OMNet 是几年前用过的,现在都忘得差不多了,有问题你可以加入OMnet的maillist发信询问,OMNet社区的人都是很kind的
    2007-06-28 16:09:35