基于独立的有状态的Reader和Writer基实现ReaderWriter类
Implementing a ReaderWriter class based upon separate stateful Reader and Writer bases
假设我有两个类…
我们可以称第一个为FooReader
,它看起来像这样:
class FooReader {
public:
FooReader(const Foo* const foo)
: m_foo(foo) {
}
FooData readFooDataAndAdvance() {
// the point here is that the algorithm is stateful
// and relies upon the m_offset member
return m_foo[m_offset++];
}
private:
const Foo* const m_foo;
size_t m_offset = 0; // used in readFooDataAndAdvance
};
我们可以把第二个称为FooWriter
,它看起来像这样:
class FooWriter {
public:
FooWriter(Foo* const foo)
: m_foo(foo) {
}
void writeFooDataAndAdvance(const FooData& foodata) {
// the point here is that the algorithm is stateful
// and relies upon the m_offset member
m_foo[m_offset++] = foodata;
}
private:
Foo* const m_foo;
size_t m_offset = 0;
};
这两种方法都能很好地发挥作用。现在假设我想创建一个FooReaderWriter
类。注意
我很自然地想说这个新类是"FooReader
"answers"FooWriter
";接口只是两个类的合并,语义保持不变。我不想重新实现完美的成员函数。
可以使用继承对这种关系建模,如下所示:
class FooReaderWriter : public FooReader, public FooWriter { };
这很好,因为我得到了共享接口,我得到了实现,我很好地建模了类之间的关系。但是也存在一些问题:
-
m_offset
成员对于每个基类型是单独的,但它们需要共享它(即调用readFooDataAndAdvance
和writeFooDataAndAdvance
都应该推进相同的m_offset
成员)。
Foo*
成员在基类中是重复的。这是在浪费内存。我不能使用PIMPL模式并将m_foo
和m_offset
存储在那里,因为我会失去m_foo
指针在基础FooReader
类中的const-ness。
我还能做些什么来解决这些问题,而不重新实现这些类中包含的功能?
这似乎已经为mixin模式准备好了。最基本的基类只声明成员:
template <class T>
class members {
public:
members(T* f) : m_foo(f) { }
protected:
T* const m_foo;
size_t m_offset = 0;
};
然后我们在它周围写一些包装符来增加阅读:
template <class T>
struct reader : T {
using T::T;
Foo readAndAdvance() {
return this->m_foo[this->m_offset++];
};
};
和写作:
template <class T>
struct writer : T {
using T::T;
void writeAndAdvance(Foo const& f) {
this->m_foo[this->m_offset++] = f;
}
};
然后在适当的时候使用
using FooReader = reader<members<Foo const>>;
using FooWriter = writer<members<Foo>>;
using FooReaderWriter = writer<reader<members<Foo>>>;
CRTP.
template<class Storage>
class FooReaderImpl {
public:
FooData readFooDataAndAdvance() {
// the point here is that the algorithm is stateful
// and relies upon the m_offset member
return get_storage()->m_foo[get_storage()->m_offset++];
}
private:
Storage const* get_storage() const { return static_cast<Storage const*>(this); }
Storage * get_storage() { return static_cast<Storage*>(this); }
};
template<class Storage>
class FooWriterImpl {
public:
void writeFooDataAndAdvance(const FooData& foodata) {
// the point here is that the algorithm is stateful
// and relies upon the m_offset member
get_storage()->m_foo[get_storage()->m_offset++] = foodata;
}
private:
Storage const* get_storage() const { return static_cast<Storage const*>(this); }
Storage * get_storage() { return static_cast<Storage*>(this); }
};
template<class T>
struct storage_with_offset {
T* m_foo = nullptr;
std::size_t m_offset = 0;
};
struct FooReader:
FooReaderImpl<FooReader>,
storage_with_offset<const Foo>
{
FooReader(Foo const* p):
storage_with_offset<const Foo>{p}
{}
};
struct FooWriter:
FooWriterImpl<FooWriter>,
storage_with_offset<Foo>
{
FooWriter(Foo* p):
storage_with_offset<Foo>{p}
{}
};
struct FooReaderWriter:
FooWriterImpl<FooReaderWriter>,
FooReaderImpl<FooReaderWriter>,
storage_with_offset<Foo>
{
FooReaderWriter(Foo const* p):
storage_with_offset<Foo>{p}
{}
};
如果你需要一个运行时多态的抽象接口,继承FooReaderImpl
和FooWriterImpl
。
此时,FooReaderWriter
服从FooReader
和FooWriter
的ducktype契约。因此,如果您使用类型擦除而不是继承,则(在使用时)它将满足任何一种要求。
using FooReader = std::function<FooData()>;
using FooWriter = std::function<void(FooData const&)>;
,然后实现对FooReaderWriter
的多重签名std::function
。但是我很奇怪,而且有点精神错乱。
相关文章:
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- 基于独立的有状态的Reader和Writer基实现ReaderWriter类