接口传递接口的容器

时间:2018-11-28 17:10:06

标签: c++ oop iterator

如果存在具有以下方法签名的接口,

class Interface2
{
public:
    virtual ~Interface2() {}
    virtual uint getId() = 0;
    virtual std::string getName() = 0;
};

class Interface
{
public:
    virtual ~Interface(){}
    virtual std::list<Interface2*> getData(uint id) = 0;
};

因此,getData(uint id)的基本目的是公开Interface2接口的内部存储空间

实施具体类Interface时,它将保留由Interface2具体类组成的对象的存储。

例如,以下可能是实现这些接口的一种方式

class Interface2Imp : public Interface2
{
public:
    uint getId() { return id;}
    std::string getName() { return name;}

private:
    uint id;
    std::string name;
};

class InterfaceImp : public Interface
{
public:
    std::list<Interface2*> getData(uint id)
    {
        std::list<Interface2*> returnList;
        std::list<Interface2Imp> & a = storage[id];
        for(auto & it : a)
        {
            returnList.push_back(&it);
        }
        return returnList;
    }

private:
    std::map<int, std::list<Interface2Imp> > storage;
}

但是,看看getData(uint id)的实现方式,我们可以看到它在其内部存储上进行了迭代,然后再次将其填充到接口列表中,这看起来很昂贵(而且很丑陋)。

是否有更好的方法来公开恰好也作为接口公开的接口内部数据?

3 个答案:

答案 0 :(得分:2)

按原样进行迭代和复制。该类存储一个X实例的列表,您需要一个指向X实例的指针的列表。这是两件事。您也许可以做一些std :: algorithm之类的事情,但这并不能改变必须完成迭代和克隆的事实。

如何更改接口和实现。使类InterfaceImp将shared_ptr的列表存储到Interface,并使getData方法返回shared_ptrs的列表。现在,容器可以直接返回其数据。 (而且您也不会移动原始指针)

话虽如此,您目前拥有的是更好的封装。您没有将内部数据公开给呼叫者,而是在克隆它。

答案 1 :(得分:1)

您所拥有的基本上是multimap<int, Interface2Imp>,但有一点曲折:外部用户需要查看Interface2*而不是Interface2Imp&

这是 iterator适配器的模型用例。您可以从Boost窃取一个或编写自己的一个。在后一种情况下,您需要一个类,其中包含一个真实的multimap<int, Interface2Imp *>::const_iterator成员,将大多数迭代器y方法直接转发给该成员,并且仅以稍微不同的方式适应operator *()operator ->()(返回内部成员返回,但向上转换为基类的指针/引用。

如果即使在迭代器适配器的私有部分中也不想提及Interface2Imp,请使用Pimpl惯用法进一步隐藏它。

答案 2 :(得分:1)

另一种解决方案是将接口实现实例的智能指针存储在第一位置:

class InterfaceImp : public Interface
{
public:
    const std::list<std::shared_ptr<Interface2>>& getData(uint id)
    {
        return storage[id];
    }

private:
    std::map<uint, std::list<std::shared_ptr<Interface2>> > storage;
}

如果您需要访问Interface2Imp实例以访问函数或数据,则无法通过Interface2看到它,您可以始终将static_cast<Interface2Imp*>与这些实例一起使用,因为您的{{1} }类知道用于实例化InterfaceImp实现的内容。
甚至有必要,甚至可以使用std::shared_ptr<Interface2>进行完整的运行时查询,并且不会影响应用程序的性能。