c++ - 剥离成员函数的正确方法

标签 c++

我有一个带有线程安全 getter 和 setter 的简单 IO 类。 它看起来像这样:

template <class IO>
class LIO : public LThreadSafe
{
    public:
        LIO() {}
        IO getValue()
        {
            this->lock();
            IO ret = value;
            this->unlock();

            return ret;
        }
        void setValue( IO newval )
        {
            this->lock();
            value = newval;
            this->unlock();
        }

        LInput<IO> *toInput()
        {
            return (LInput<IO> *)this;
        }

    private:
        IO value;

有些类需要能够读取和写入这些 IO。 而其他人应该只被允许阅读。 所以我创建了一个输入类,我可以将我的 IO 类转换为

template <class IO>
class LInput : public LThreadSafe
{
    public:
        LInput() {}
        IO getValue()
        {
            this->lock();
            IO ret = value;
            this->unlock();

            return ret;
        }

    private:
        IO value;

这是好的做法吗? 为此创建一个全新的类似乎有些过分。

解决方案

我最终选择了多重继承。一旦我对 shared_ptr 和 C++ 有了更多的了解,就会再次查看这个线程。 希望我能多按几次向上箭头...

最佳答案

据我所知,有两种方法。

使用子类

您可以使 LInput 私有(private)继承自 LIO,但将输入法标记为公共(public):

template <typename IO>
class LIO : public LThreadSafe
{
public:
    LIO() {}
    LIO(const LIO& in) { /* make a copy for read-only */ }
    LIO(LIO& io) { /* make a copy for write-only */ }

    shared_ptr<LInput<IO>> toInput() const { return make_shared<LInput<IO>>(*this); }
    shared_ptr<LOutput<IO>> toOutput() { return make_shared<LOutput<IO>>(*this); }
};

template <class IO>
class LInput : private LIO
{
public:
    LInput(LIO<IO>* pio) : LIO<IO>(*pio) {}
    using LIO<IO>::getValue;
};

LInput<int> in;
auto v = in.getValue();        // OK

in.setValue(xyz);              // Error: inaccessible
LIO<int>& io = in;                  // Error: inaccessible

再考虑一下这个解决方案,当IO对象可以被复制时,你会发现它很好;如果无法复制,则需要将实现类引用包装在 LIO 类中。

如果你不能复制,一个完整的例子是:

template <typename IO> class LIOImpl {};

template <typename IO> class LInput;
template <typename IO> class LOutput;

template <typename IO> class LIO {
  shared_ptr<LIOImpl<IO> > pimpl_;

public:
  LIO() : pimpl_(make_shared<LIOImpl<IO> >()) {}
  LIO(const LIO &io) : pimpl_(io.pimpl_) {}

  IO getValue() const { ... }

  LInput<IO> toInput() const { return LInput<IO>(*this); }
  LOutput<IO> toOutput() { return LOutput<IO>(*this); }
};

template <class IO> class LInput : private LIO<IO> {
public:
  LInput(const LIO<IO> &io) : LIO<IO>(io) {}
  using LIO<IO>::getValue;
};

template <class IO> class LOutput : private LIO<IO> {
public:
  LOutput(LIO<IO> io) : LIO<IO>(io) {}
  using LIO<IO>::setValue;
};

使用多重继承

C++ STL iostream使用多重继承的方式来实现istreamostream。约束在层次结构中被拉高。这种菱形继承(钻石问题)有时被认为是一种不好的做法。

这种下推约束方法避免了菱形继承

您还可以使用菱形继承(钻石问题),使用纯类作为接口(interface):

template <typename IO>
class LInput
{
public:
    virtual IO getValue() const = 0;
};

template <typename IO>
class LOutput
{
public:
    virtual void setValue(const IO& v) const = 0;
};

template <typename IO>
class LIO : public LInput<IO>, public LOutput<IO>, public LThreadSafe
{
public:
    IO getValue() const override { ... }
    void setValue(const IO& v) const override { ... }

    LInput<IO>* toInput() const { return this; }
    LOutput<IO>* toOutput() { return this; }
};

选择您感觉良好的方式,同时尝试将接口(interface)与实现隔离开来。一旦达到限制(或者您不再喜欢它),您可以轻松更改界面而无需重新实现。

顺便说一句,如果你使用的是 C++ 11,你应该使用 std::lock_guard而不是手写 lock/unlock 对:

{
    lock_guard<LThreadSafe> lock;
    // ok you have lock now.
} 
// here lock is automatically released

关于c++ - 剥离成员函数的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20656058/

相关文章:

c++ - std::unordered_map 指针/引用失效

c++ - 为什么我的程序最多只能编译 16 条记录?

C++ 在可变内存中声明一个字符串文字

c++ - 窗口坐标到摄像机角度?

c++ - C++中的数组类成员初始化

c++ - Arduino IDE 在单独的文件中初始化 char[]

c++ - 使用 C++ 处理 firefox 错误消息 “Cannot load XPCOM”

c++ - 抽象/重构此开关/案例的好方法是什么?

c++ - 除了 memcpy 之外,bit_cast 还会有什么额外的 UB?

c++ - 基于枚举调用适当的函数,但使用模板