抽象数据类型之容器(一)

本文深入探讨抽象容器的概念,介绍容器类如何作为Object的子类,能够存储其他对象。同时,文章讨论了Visitor模式在容器类中的应用,通过Visitor类与仿函数的比较,阐述了如何利用C++11的std::function和std::bind增强设计的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        本系列文章基于我之前的“抽象数据类型与类层次”系列,专门讲解“抽象容器”及其相关概念。(点击打开链接


一、容器类    

        根据上面的类层次图,容器也是一种“Object”。容器是一种能够存储其他物体的物体。下面使用一个容器类来抽象容器这个概念。

<span style="font-size:14px;">#pragma once
#include "Object.h"
#include "OwnerShip.h"
#include "Visitor.h"
#include "Iterator.h"

class Container : public virtual Object, public virtual OwnerShip
{
public:
    virtual unsigned int Count() const;
    virtual bool IsEmpty() const;
    virtual bool IsFull() const;
    //virtual std::hash<Object> Hash() const;
    virtual void Put(std::ostream &)const;
    virtual Iterator & NewIterator() const;

    virtual void Purge() = 0;
    virtual void Accept(Visitor &) const = 0;
protected:
    Container();
    unsigned int count;
};
</span>

注:容器类是一种抽象类,并不产生实际的具体对象,故其构造函数可以是“Protercted”。

<span style="font-size:14px;">#include "stdafx.h"
#include "Container.h"
#include "NullIterator.h"
#include <typeinfo>


Container::Container()
    : count(0)
{
}

unsigned int Container::Count() const
{
    return count;
}

bool Container::IsEmpty() const
{
    return Count() == 0;
}

bool Container::IsFull() const
{
    return false;
}

void Container::Put(std::ostream & s) const
{
    PuttingVisitor visitor(s);

    s << typeid(*this).name() << " {";
    Accept(visitor);
    s << "}";
}

Iterator & Container::NewIterator() const
{
    return *new NullIterator();
}
</span>

注:“IsEmpty函数”中使用的不是成员变量来直接判断,是因为考虑到容器的子类对计数或空容器的判断方法可能重载。


二、Visitor类

        在上面容器类中,有一个“Accept接口函数”,该函数需要一个Vistitor类引用作为参数。这个接口用到的就是Visitor Pattern(访问者模式)。

<span style="font-size:14px;">class Visitor
{
public:
    virtual void Visit(Object &) = 0;
    virtual bool IsDone() const { return false; }
};</span>

        Visitor类其实非常简单,它只有两个接口函数,其中“Visit函数”接受一个Object引用为参数,对该Object对象进行某些处理。因此,Visitor与Container有一个交互,这个交互过程是这样的:Container通过调用Accept函数接受一个Visitor,即接受一种算法或处理方式,然后遍历Container的各个元素,将元素逐个传递给Visitor,对他们逐个进行Visit操作(算法)。这其实也是一种将算法与待处理对象分离的设计方法。

<span style="font-size:14px;">void SomeContainer::Accept (Visitor& visitor) const
    for each Object i in this container
        if (visitor.IsDone ())
            return;
        visitor.Visit (i);</span>

<span style="font-size:14px;"><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">        Visitor类的另一个函数“IsDone”可以作为“Accept函数”中的循环中断条件。</span></span>
<span style="font-size:14px;"><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">        下面再展示几个具体的Visitor类和全部代码:</span></span>

<span style="font-size:14px;">#ifndef VISITOR_H
#define VISITOR_H

#include "Object.h"
#include <ostream>

class Visitor
{
public:
    virtual void Visit(Object &) = 0;
    virtual bool IsDone() const { return false; }
};

class PuttingVisitor : public Visitor
{
public:
    PuttingVisitor(std::ostream & s)
        : stream(s), comma(false)
    {}

    void Visit(Object & object)
    {
        if (comma)
            stream << ", ";
        stream << object;
        comma = true;
    }

private:
    std::ostream & stream;
    bool comma;
};

class MatchingVisitor : public Visitor
{
public:
    MatchingVisitor(Object const & object)
        : target(object), found(NULL)
    {}

    void Visit(Object & object)
    {
        if (found == NULL && object == target)
            found = &object;
    }

    bool IsDone() const { return found != NULL; }

private:
    Object const & target;
    Object * found;
};

#endif // VISITOR_H</span>

        返回Container的实现代码看“Put函数”,它里面也用到了一种Visitor。实际上,Visitor是对操作(算法)的一种抽象,不针对具体对象,故它可以用于Accept函数,也可用在其他地方,提高代码复用。这就是Visitor Pattern的优势。


三、Visitor类与仿函数

        先看“PuttingVisitor”,它的功能其实可以用一个函数指针来代替。设计一个函数指针,它接受一个Object &参数。再看“MatchingVisitor”,它的功能其实也可以用一个函数对象来代替,只需要在这个函数对象构造的时候给它传递一个参数。此外,使用C++11中的std::function(函数对象包装器)和std::bind,可以将这种设计变得更通用化。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值