我知道如何创建可应用于不同对象的单个界面。那不是我想要的。我想要相反的行为:我想找到一种机制来为同一个对象提供不同的接口,而无需为虚拟呼叫付费。
基本上,假设我有一个队列,使用方法PushMessage,PopMessage和IsEmpty:
class Queue
{
public:
void PushMessage(Message message);
Message PopMessage();
bool IsEmpty() const;
}
我想向某人提供此队列的句柄,但只让他们调用PopMessage和IsEmpty,并将其他人的句柄交给同一队列,只允许他们调用PushMessage。因此,队列的所有者决定谁可以写入它以及谁可以从中删除消息。
我的一个想法是创建两个类,它们不包含自己的数据成员,但继承自Queue并提供代理方法:
struct EnQueueer
: private Queue
{
void PushMessage(Message message){Queue::PushMessage(message);}
}
struct DeQueueer
: private Queue
{
Message PopMessage(){ return Queue::PopMessage();}
bool IsEmpty() const{ return Queue::IsEmpty();}
}
但我不确定这是否安全。原始队列的所有者必须向EnQueueer或DeQueueer转发,我不确定是完全正确的。而且,编译器不喜欢它:
static_cast<DeQueueer*>(&m_queue); // Results in compile error:
// 'Queue' is an inaccessible base of 'DeQueueer'
reinterpret_cast解决了这个问题,但我不确定它是否安全。只要派生类没有自己的成员,它是否安全?
答案 0 :(得分:4)
您始终可以利用隐式转换,并拥有一个包裹Queue
的对象。
class EnQueueer {
public:
// implicitly convert to Queue
EnQueueer(const Queue& queue) : m_queue(queue) { }
operator Queue() cont { return m_queue; }
void PushMessage(Message m) { m_queue.PushMessage(m); }
private:
Queue& m_queue;
};
为了利用不同的实现,请使用模板魔术:
template<typename Q>
class EnQueueer {
public:
// implicitly convert to Queue
EnQueueer(const Q& queue) : m_queue(queue) { }
operator Q() cont { return m_queue; }
void PushMessage(Message m) { m_queue.PushMessage(m); }
private:
Q& m_queue;
};
如果你想要,你可以利用模板中的C ++概念......但不是太必要的IMO。
请注意EnQueueer
包含对队列的引用,这对于队列的生命周期来说非常重要,因为它包含EnQueueer的生命周期。你不能存储EnQueueer并让Queue死掉。安全使用包括替换函数调用和声明,这些函数可以在Queue&
等EnQueueer
之后正常工作。