如何为单个对象创建不同的接口?

时间:2014-12-20 18:51:06

标签: c++

我知道如何创建可应用于不同对象的单个界面。那不是我想要的。我想要相反的行为:我想找到一种机制来为同一个对象提供不同的接口,而无需为虚拟呼叫付费。

基本上,假设我有一个队列,使用方法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解决了这个问题,但我不确定它是否安全。只要派生类没有自己的成员,它是否安全?

1 个答案:

答案 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之后正常工作。