代码之家  ›  专栏  ›  技术社区  ›  Arkaitz Jimenez

C++、多态与迭代器

  •  5
  • Arkaitz Jimenez  · 技术社区  · 15 年前

    我希望有一个存储接口(抽象类)和一组存储实现(SQLite、MySQL、Memcached..),用于存储已知类的对象和从存储中检索子集。
    对我来说,清晰的界面是:

    class Storable{int id; blah; blah; blah; string type;};
    class Storage{
        virtual Storage::iterator get_subset_of_type(string type) = 0;
        virtual Storage::iterator end)_ = 0;
        virtual void add_storable(Storable storable) = 0;
    };
    

    然后创建实现接口的存储实现。现在,我的问题是:

    • 迭代器不能是多态的,因为它们是按值返回的。
    • 我不能为给定的存储实现将Storage::iterator子类化
    • 我考虑过使用包装器迭代器包装存储实现子类的多态类型并对其执行pimpl,但是之后我需要使用动态内存并在所有地方进行分配。

    有什么线索吗?

    8 回复  |  直到 15 年前
        1
  •  3
  •   Steve Jessop    15 年前

    如果你想要一个迭代的虚拟接口,像这样?

    #include <iostream>
    #include <iterator>
    
    struct Iterable {
        virtual int current() = 0;
        virtual void advance() = 0;
      protected:
        ~Iterable() {}
    };
    
    struct Iterator : std::iterator<std::input_iterator_tag,int> {
        struct Proxy {
            int value;
            Proxy(const Iterator &it) : value(*it) {}
            int operator*() { return value; }
        };
        Iterable *container;
        Iterator(Iterable *a) : container(a) {}
        int operator*() const { return container->current(); }
        Iterator &operator++() { container->advance(); return *this; }
        Proxy operator++(int) { Proxy cp(*this); ++*this; return cp; }
    };
    
    struct AbstractStorage : private Iterable {
        Iterator iterate() {
            return Iterator(this);
        }
        // presumably other virtual member functions...
        virtual ~AbstractStorage() {}
    };
    
    struct ConcreteStorage : AbstractStorage {
        int i;
        ConcreteStorage() : i(0) {}
        virtual int current() { return i; }
        virtual void advance() { i += 10; }
    };
    
    int main() {
        ConcreteStorage c;
        Iterator x = c.iterate();
        for (int i = 0; i < 10; ++i) {
            std::cout << *x++ << "\n";
        }
    }
    

    这不是一个完整的解决方案-我还没有实现 Iterator::operator== ,或 Iterator::operator-> (如果包含的类型是类类型,则需要后者)。

    我将状态存储在ConcreteStorage类中,这意味着不能在同一个存储上同时有多个迭代器。所以可能不是 Iterable 作为存储的基类,需要另一个存储的虚拟函数来返回新的 可迭代的 . 它只是一个输入迭代器,这意味着迭代器的副本都可以指向同一个 可迭代的 ,以便可以使用 shared_ptr (或者 Itertable 应该有一个虚拟析构函数,或者newIterator函数应该返回 共享的 ,或者两者都有)。

        2
  •  2
  •   Å imon Tóth    15 年前

    我没有看到存储的好处是多态的。

    无论如何,注意迭代器根本不需要多态性。

    它只需要使用存储类中的虚拟方法来实现其功能。这些方法可以很容易地在子代中重写(创建所需的功能)。

        3
  •  1
  •   Charles Salvia    15 年前

    我不太清楚为什么这是个问题。您只需要实现所有迭代器运算符(增量、解引用等),以便它们调用 Storage 反对。

        4
  •  1
  •   Jerry Coffin    15 年前

    使用数据库引擎进行存储的事实并没有改变这样一个事实,即这里的内容基本上是一个容器类。

    简而言之,您几乎肯定应该使用在所存储的对象类型上实例化的类模板。存储引擎中的变量可以通过继承或第二个模板参数来处理。使用模板参数会产生编译时多态性,而继承会产生运行时多态性(即,您可以在运行时更改存储引擎)。

    你可能想看看 DTL 为了一些灵感(或者你可以省去很多麻烦,在遇到问题之前或者除非遇到问题之前使用它)。

        5
  •  0
  •   lijie    15 年前

    这似乎是一个动态分配与更改迭代器状态大小(无需重新编译客户端)能力的对比案例。

        6
  •  0
  •   eddyxu    15 年前

    您可以尝试boost::iterator,它提供了几个适配器和外观。

    http://www.boost.org/doc/libs/1_45_0/libs/iterator/doc/index.html

        7
  •  0
  •   alexeiz    15 年前

    看看adobe::any_iterator或任何_iterator的其他实现(http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html)。它实现了一个多态迭代器概念,但是您仍然可以处理任何按值迭代器(按值返回、按值传递等)。

        8
  •  0
  •   itaj    15 年前

    实际使用不同类型容器的算法代码必须用模板函数(可能是成员函数)编写,模板函数通过模板的参数获取类型。 在编译时解析的。对于模板函数的每个实例,确切的迭代器类型都是已知的。

    如果确实需要运行时解析,则需要添加一个分派来调用上述模板函数的不同实例。虚拟函数应该调用实际的算法模板函数,但这将是某个模板类中的虚拟函数重写(即,将为每个实例分别编译虚拟函数并调用算法模板函数的不同实例)。 如果你需要双重/多重派遣,那就做吧。可惜c++不支持函数在多个参数上是虚拟的,所以必须使用任何常用的方法进行双重分派。但对实际算法函数的调用应该在调度解决后进行。