有什么方法可以修改它的子项中的嵌套 类 实现吗?
Is there any way to modify a nested classes implementation in it's children?
我想要一个 class 接口(我们称它为 class A),它可以在我的代码中以不同的方式继承和实现,并且该接口包含一些函数,包括一个 stl 类型的迭代器, 定义为嵌套 class。
我的问题是,每当我尝试继承接口(让我们调用 class B)以及迭代器并实现它们时,继承的开始和结束 class 期望类型为 A::iterator 的迭代器,即使 B class 中的迭代器继承自 A::iterator。我知道多态性仅适用于 pointers/references,但我如何才能做到这一点?
我也试过和朋友 classes 一起做,但我不太清楚它们是如何工作的,因为我以前从未使用过它们,所以结果有点乱。这是一些示例代码(我实际上 运行)
class A
{
public:
class iterator
{
public:
virtual Entity& operator*() const = 0;
virtual bool operator!=(const iterator) const = 0;
virtual bool valid() const = 0;
virtual iterator& operator=(const iterator& it) = 0;
virtual iterator operator++() = 0;
virtual iterator operator++(int) = 0;
virtual ~iterator() {};
};
virtual int add(const std::vector<std::string>& params) = 0;
virtual int remove(const std::vector<std::string>& params) = 0;
virtual int update(const std::vector<std::string>& params) = 0;
virtual int save(const std::vector<std::string>& params) = 0;
virtual int size() = 0;
virtual typename iterator begin() = 0;
virtual typename iterator end() = 0;
virtual ~A() {}
};
class B: public A
{
private:
std::vector<Entity> elements;
public:
class iterator : public A::iterator
{
private:
std::vector<Entity>::iterator ptr;
B& repo;
public:
iterator(std::vector<Entity>::iterator ptr, B& container) : ptr{ ptr }, repo{ container }{}
Entity& operator*() const override;
bool operator!=(const iterator) const override;
bool valid() const override;
iterator& operator=(const iterator& it) override;
iterator operator++() override;
iterator operator++(int) override;
};
B() : elements{ std::vector<Entity>() } {}
int add(const std::vector<std::string>& params) override;
int remove(const std::vector<std::string>& params) override;
int update(const std::vector<std::string>& params) override;
int save(const std::vector<std::string>& params) override;
int size() override;
typename iterator begin();
typename iterator end();
~B() {};
};
我想这样做的原因是因为我必须创建 2 个不同的存储库,一个使用文件,一个在内存中,也许将来需要一个数据库,但我就是无法获得迭代器正确的继承它。返回 std::vector 会快很多,但也有点作弊。
编辑:我最终想要实现的是拥有两个具有相同接口并且也可以迭代的存储库,其中一个在 std::vector 上实现,另一个直接在文件上实现。这意味着 vector repo 的迭代器必须只给我 const std::vector 迭代器,而另一个迭代器必须以只读方式打开文件、转到下一行等。我必须让它们与基于 for 循环的范围兼容。
我设法通过 return 引用迭代器而不是对象来直截了当地解决了这个问题。因此,我总是必须在主函数中保留一个我可以引用的指针和 return,但至少它可以工作。问题正如评论中提到的那样:多态性仅适用于指针和引用。
您似乎在寻找类型擦除:一种支持不同实现的类型,但可以被其他代码用作单一类型,因为该类型,而不仅仅是指针和引用,可以是复制等。设置它的常用方法是非多态 class,其中包含指向多态接口的指针:
#include <utility>
#include <memory>
#include <vector>
struct Entity {};
class A
{
protected:
class IterInterface
{
public:
virtual ~IterInterface() = default;
virtual std::unique_ptr<IterInterface> clone() const = 0;
virtual Entity& dereference() const = 0;
virtual void increment() = 0;
virtual bool equal_to(const IterInterface& other) const = 0;
};
virtual std::unique_ptr<IterInterface> begin_impl() = 0;
virtual std::unique_ptr<IterInterface> end_impl() = 0;
public:
class iterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = Entity;
using reference = Entity&;
using pointer = Entity*;
using difference_type = std::ptrdiff_t;
iterator() = default;
iterator(const iterator& it)
{
if (it.m_impl)
m_impl = it.m_impl->clone();
}
iterator(iterator&&) noexcept = default;
iterator& operator=(const iterator& it)
{
if (it.m_impl)
m_impl = it.m_impl->clone(); // self-assignment-safe
else
m_impl = nullptr;
return *this;
}
iterator& operator=(iterator&&) noexcept = default;
explicit iterator(std::unique_ptr<IterInterface> && impl)
: m_impl(std::move(impl)) {}
Entity& operator*() const
{ return m_impl->dereference(); }
iterator& operator++()
{ m_impl->increment(); return *this; }
iterator operator++(int) const
{
iterator copy = *this;
m_impl->increment();
return copy;
}
friend bool operator==(const iterator &it1, const iterator &it2)
{
bool it1_ok(it1.m_impl);
bool it2_ok(it2.m_impl);
if (it1_ok && it2_ok)
return it1.m_impl->equal_to(*it2.m_impl);
else
return it1_ok == it2_ok;
}
friend bool operator!=(const iterator &it1, const iterator &it2)
{ return !(it1 == it2); }
private:
std::unique_ptr<IterInterface> m_impl;
};
iterator begin()
{ return iterator(begin_impl()); }
iterator end()
{ return iterator(end_impl()); }
// ...
};
class B : public A
{
public:
// ...
private:
std::vector<Entity> elements;
class IterImpl : public IterInterface
{
public:
explicit IterImpl(std::vector<Entity>::iterator viter)
: m_viter(viter) {}
std::unique_ptr<IterInterface> clone() const override
{ return std::make_unique<IterImpl>(m_viter); }
Entity& dereference() const override { return *m_viter; }
void increment() override { ++m_viter; }
bool equal_to(const IterInterface& other) const override
{
if (auto* oimpl = dynamic_cast<const IterImpl*>(&other))
return m_viter == oimpl->m_viter;
// "other" isn't even from a B.
return false;
}
private:
std::vector<Entity>::iterator m_viter;
};
std::unique_ptr<IterInterface> begin_impl() override
{ return std::make_unique<IterImpl>(elements.begin()); }
std::unique_ptr<IterInterface> end_impl() override
{ return std::make_unique<IterImpl>(elements.end()); }
};
我想要一个 class 接口(我们称它为 class A),它可以在我的代码中以不同的方式继承和实现,并且该接口包含一些函数,包括一个 stl 类型的迭代器, 定义为嵌套 class。
我的问题是,每当我尝试继承接口(让我们调用 class B)以及迭代器并实现它们时,继承的开始和结束 class 期望类型为 A::iterator 的迭代器,即使 B class 中的迭代器继承自 A::iterator。我知道多态性仅适用于 pointers/references,但我如何才能做到这一点?
我也试过和朋友 classes 一起做,但我不太清楚它们是如何工作的,因为我以前从未使用过它们,所以结果有点乱。这是一些示例代码(我实际上 运行)
class A
{
public:
class iterator
{
public:
virtual Entity& operator*() const = 0;
virtual bool operator!=(const iterator) const = 0;
virtual bool valid() const = 0;
virtual iterator& operator=(const iterator& it) = 0;
virtual iterator operator++() = 0;
virtual iterator operator++(int) = 0;
virtual ~iterator() {};
};
virtual int add(const std::vector<std::string>& params) = 0;
virtual int remove(const std::vector<std::string>& params) = 0;
virtual int update(const std::vector<std::string>& params) = 0;
virtual int save(const std::vector<std::string>& params) = 0;
virtual int size() = 0;
virtual typename iterator begin() = 0;
virtual typename iterator end() = 0;
virtual ~A() {}
};
class B: public A
{
private:
std::vector<Entity> elements;
public:
class iterator : public A::iterator
{
private:
std::vector<Entity>::iterator ptr;
B& repo;
public:
iterator(std::vector<Entity>::iterator ptr, B& container) : ptr{ ptr }, repo{ container }{}
Entity& operator*() const override;
bool operator!=(const iterator) const override;
bool valid() const override;
iterator& operator=(const iterator& it) override;
iterator operator++() override;
iterator operator++(int) override;
};
B() : elements{ std::vector<Entity>() } {}
int add(const std::vector<std::string>& params) override;
int remove(const std::vector<std::string>& params) override;
int update(const std::vector<std::string>& params) override;
int save(const std::vector<std::string>& params) override;
int size() override;
typename iterator begin();
typename iterator end();
~B() {};
};
我想这样做的原因是因为我必须创建 2 个不同的存储库,一个使用文件,一个在内存中,也许将来需要一个数据库,但我就是无法获得迭代器正确的继承它。返回 std::vector 会快很多,但也有点作弊。 编辑:我最终想要实现的是拥有两个具有相同接口并且也可以迭代的存储库,其中一个在 std::vector 上实现,另一个直接在文件上实现。这意味着 vector repo 的迭代器必须只给我 const std::vector 迭代器,而另一个迭代器必须以只读方式打开文件、转到下一行等。我必须让它们与基于 for 循环的范围兼容。
我设法通过 return 引用迭代器而不是对象来直截了当地解决了这个问题。因此,我总是必须在主函数中保留一个我可以引用的指针和 return,但至少它可以工作。问题正如评论中提到的那样:多态性仅适用于指针和引用。
您似乎在寻找类型擦除:一种支持不同实现的类型,但可以被其他代码用作单一类型,因为该类型,而不仅仅是指针和引用,可以是复制等。设置它的常用方法是非多态 class,其中包含指向多态接口的指针:
#include <utility>
#include <memory>
#include <vector>
struct Entity {};
class A
{
protected:
class IterInterface
{
public:
virtual ~IterInterface() = default;
virtual std::unique_ptr<IterInterface> clone() const = 0;
virtual Entity& dereference() const = 0;
virtual void increment() = 0;
virtual bool equal_to(const IterInterface& other) const = 0;
};
virtual std::unique_ptr<IterInterface> begin_impl() = 0;
virtual std::unique_ptr<IterInterface> end_impl() = 0;
public:
class iterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = Entity;
using reference = Entity&;
using pointer = Entity*;
using difference_type = std::ptrdiff_t;
iterator() = default;
iterator(const iterator& it)
{
if (it.m_impl)
m_impl = it.m_impl->clone();
}
iterator(iterator&&) noexcept = default;
iterator& operator=(const iterator& it)
{
if (it.m_impl)
m_impl = it.m_impl->clone(); // self-assignment-safe
else
m_impl = nullptr;
return *this;
}
iterator& operator=(iterator&&) noexcept = default;
explicit iterator(std::unique_ptr<IterInterface> && impl)
: m_impl(std::move(impl)) {}
Entity& operator*() const
{ return m_impl->dereference(); }
iterator& operator++()
{ m_impl->increment(); return *this; }
iterator operator++(int) const
{
iterator copy = *this;
m_impl->increment();
return copy;
}
friend bool operator==(const iterator &it1, const iterator &it2)
{
bool it1_ok(it1.m_impl);
bool it2_ok(it2.m_impl);
if (it1_ok && it2_ok)
return it1.m_impl->equal_to(*it2.m_impl);
else
return it1_ok == it2_ok;
}
friend bool operator!=(const iterator &it1, const iterator &it2)
{ return !(it1 == it2); }
private:
std::unique_ptr<IterInterface> m_impl;
};
iterator begin()
{ return iterator(begin_impl()); }
iterator end()
{ return iterator(end_impl()); }
// ...
};
class B : public A
{
public:
// ...
private:
std::vector<Entity> elements;
class IterImpl : public IterInterface
{
public:
explicit IterImpl(std::vector<Entity>::iterator viter)
: m_viter(viter) {}
std::unique_ptr<IterInterface> clone() const override
{ return std::make_unique<IterImpl>(m_viter); }
Entity& dereference() const override { return *m_viter; }
void increment() override { ++m_viter; }
bool equal_to(const IterInterface& other) const override
{
if (auto* oimpl = dynamic_cast<const IterImpl*>(&other))
return m_viter == oimpl->m_viter;
// "other" isn't even from a B.
return false;
}
private:
std::vector<Entity>::iterator m_viter;
};
std::unique_ptr<IterInterface> begin_impl() override
{ return std::make_unique<IterImpl>(elements.begin()); }
std::unique_ptr<IterInterface> end_impl() override
{ return std::make_unique<IterImpl>(elements.end()); }
};