4

std::vector をコンストラクターのパラメーターとして受け取り、このベクターを使用してバイトを格納する一種のバッファー クラスがあります。このクラスには、バッファから読み書きするためのメソッドがあります。ただし、このバッファー クラスに const std::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;
}

個別のライター クラスとリーダー クラス (同様のロジックを 2 つの異なるクラスに分離するのは良くない) を使用せずに、書き込みアクセスのコンパイル時チェックを使用してこれを達成する方法はありますか? const_casts を他の安全でないハックに使用したくありません。また、解決策として別のパターン/アーキテクチャを自由に提案してください。

編集:

回答ありがとうございます。3 つの回答から、user315052 のファサード パターンは、IMO const_cast または複数のポインターがいくつかのクラスを持つよりも悪いため、私が望んでいたものに最も近いものでした。また、もう少し調査を行ったところ、テンプレートを使用して const 型と非 const 型を選択するこのSO q/a に出くわしました。今、私は次のようなものを持っていて、それは完璧に動作します.constバージョンで書き込みを呼び出そうとすると、コンパイル時に「メソッドエラーはありません」. すべてのテンプレートやその他のもののために、コードは少し醜くなりましたが、コンパイル時にエラーが発生することは、例外よりもはるかに優れています。

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:

};
4

3 に答える 3

1

デザインについてはよくわかりませんが、ご要望に似たものを作ることができます (それが良いアイデアかどうかは別の議論です)。

最初に、参照を 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が const の場合、writeBufferポインターは設定されません。if (writeBuffer)関数を使用してテストできwriteます。バッファを変更しないためread、関数としてマークする必要があることに注意してください。const

そうは言っても、あなたはまだデザインにもっと取り組む必要があります. 宣言されているreadandwrite関数はおそらく十分ではありません。何を読み書きする必要がありますか?最初/最後の値? データを追加/消費する必要があります (この場合、どちらreadreadBufferすべきではありませんconst)...

于 2012-08-17T21:51:33.417 に答える
1

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(); }
    //...
};

BufferInterface読み取り専用バージョンと読み取り/書き込みバージョンの両方で再利用される一般的なロジックを実装できます。

于 2012-08-17T22:03:18.817 に答える
0

const キャストが言語に含まれているのには理由があります。慎重に使用する必要がありますが、これはその 1 つだと思います。私は次のようにします(構文チェックはしていません):

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
}

メソッドにconston が追加されていることに注意してください。read()コンパイラにさらに const の正確性を強制させたい場合は、次のように読み取り専用バッファを作成します。

const Buffer* buffer = new Buffer(vec);

これにより、constメソッドの呼び出しのみが許可されます。これは、2 つの完全に別個のクラスを作成しなくても安全です。

于 2012-08-17T22:08:39.160 に答える