const参数的类的只读版本



我有一种缓冲区类,它将std::vector作为构造函数参数,并使用该向量存储字节。这个类具有从缓冲区读取和向缓冲区写入的方法。然而,我想给这个缓冲区类一个conststd::vector,并且仍然能够使用读函数,而写函数应该在编译时失败,或者至少抛出一个异常。

我提出的唯一解决方案是这样的:

class Buffer
{
    public:
    Buffer(std::vector<uint8>& vec)
    { 
        this->writeVec = vec
        this->readVec = vec;
    }
    Buffer(std::vector<uint8> const& vec)
    {
        this->writeVec = null
        this->readVec = vec;
    }
    void write(uint8 i)
    {
        this->throwIfWriteVecNull();
        // do write to writeVec
    }
    uint8 read()
    {
        // do read from readVec
    }
    private:
    std::vector<uint8>& writeVec;
    std::vector<uint8> const& readVec;
}

如果没有单独的编写器和读取器类(它会将类似的逻辑分离为两个不同的类,这很不好),并且在编译时检查写访问权限,有什么方法可以实现这一点吗?我不想对任何其他不安全的黑客使用const_cast。也可以随意提出替代模式/架构作为解决方案。

编辑:

谢谢大家的回答。从这三个答案来看,user315052的facade模式最接近我想要的,因为IMO const_cast或多个指针比多几个类更糟糕。我还做了更多的研究,偶然发现了这个SOq/a,其中模板用于在常量和非常量类型之间进行选择。现在我有了如下的东西,它非常完美,如果我尝试在const版本上调用write,我在编译时会得到"无方法错误"。由于所有模板之类的原因,代码变得有点难看,但在编译时出错比异常要好得多。

template <typename BlockType, bool isMutable>
class BaseBuf : boost::noncopyable
{
public:
    typedef typename boost::mpl::if_c<isMutable, std::vector<BlockType>, std::vector<BlockType> const>::type VectorType;
    BaseBuf(VectorType& blocks) : blocks(blocks)
    {
    }
    void seekReadCursor(size_t pos)
    {
         // seek to pos
    }
    bool readBool() const
    {
         // do read from pos
    }
    //void read...
    //...
protected:
    VectorType& blocks;
};
template <typename BlockType>
class ImmuBuf : public BaseBuf<BlockType, false>
{
public:
    typedef BaseBuf<BlockType, false> Parent;
    typedef typename Parent::VectorType VectorType;
    ImmuBuf(VectorType& blocks) : Parent(blocks)
    {
    }
private:
};
template <typename BlockType>
class MutaBuf : public BaseBuf<BlockType, true>
{
public:
    typedef BaseBuf<BlockType, true> Parent;
    typedef typename Parent::VectorType VectorType;
    MutaBuf(VectorType& blocks) : Parent(blocks)
    {
    }
    // void resize()...
    void writeBool(bool b)
    {
        // do write
    }
    //void write...
    //...
private:
};

您似乎真的希望Buffer成为读/写版本和只读版本的门面。

class BufferInterface {
    friend class Buffer;
    friend class std::default_delete<BufferInterface>;
protected:
    virtual ~BufferInterface () {}
    virtual void write (uint8_t) = 0;
    virtual uint8_t read () = 0;
    //...
};
class Buffer {
    std::unique_ptr<BufferInterface> impl_;
public:
    Buffer (std::vector<uint8_t> &v) : impl_(new BufferReadWrite(v)) {}
    Buffer (const std::vector<uint8_t> &v) : impl_(new BufferReadOnly(v)) {}
    void write(uint8_t i) { impl_->write(i); }
    uint8_t read () { return impl_->read(); }
    //...
};

CCD_ 2可以实现只读版本和读/写版本都要重用的任何公共逻辑。

我对设计不确定,但我们可以尝试做一些类似于您要求的事情(这是否是一个好主意是另一个讨论)。

第一件事是引用不能为NULL,如果你想提供可选的参数,那么你应该使用指针或更高级别的构造(boost::optional)。然后您可以提供多个构造函数:

class Buffer {
   std::vector<uint8_t> const *readBuffer;
   std::vector<uint8_t>       *writeBuffer;
public:
   Buffer( std::vector<uint8_t>& v ) : readBuffer(&v), writeBuffer(&v) {}
   Buffer( std::vector<uint8_t> const & v ) : readBuffer(&v), writeBuffer() {}
   void write( uint8_t v );
   uint8_t read() const;
};

如果传递给Buffer的参数为常量,则不会设置writeBuffer指针。您可以在write函数中使用if (writeBuffer)进行测试。请注意,read应标记为const函数,因为它不会修改缓冲区。

话虽如此,你仍然需要在设计上做更多的工作。声明的readwrite函数可能不够。应该读/写什么?第一个/最后一个值?它们是否应该附加/消耗数据(在这种情况下,readreadBuffer都不应该是const)。。。

语言中的Const强制转换是有原因的。它们应该谨慎使用,但我认为这就是其中之一。我会这样做(不检查语法):

Buffer(std::vector<uint8> const& vec)
{
    this->vec = const_cast<std::vector<uint8>& >(vec);
    this->readonly = true;
}
void write(uint8 i)
{
    this->throwIfReadOnly();
    // do write to vec
}
uint8 read() const
{
    // do read from vec
}

注意在read()方法上添加了const。如果您希望编译器另外强制常量正确性,请构造一个只读缓冲区,如下所示:

const Buffer* buffer = new Buffer(vec);

这使得它只能调用const方法。在不编写两个完全独立的类的情况下,这是最安全的。

最新更新