我有一个带有线程安全 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
使用多重继承的方式来实现istream
和ostream
。约束在层次结构中被拉高。这种菱形继承(钻石问题)有时被认为是一种不好的做法。
这种下推约束方法避免了菱形继承。
您还可以使用菱形继承(钻石问题),使用纯类作为接口(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/