C ++ - 允许通过基类(接口)访问,禁止通过派生类访问(具体实现)?

时间:2013-03-22 13:04:11

标签: c++ inheritance casting abstract-class explicit-implementation

假设我有纯抽象类IHandler和我的类派生于它:

class IHandler
{
public:
   virtual int process_input(char input) = 0;
};

class MyEngine : protected IHandler
{
public:
   virtual int process_input(char input) { /* implementation */ } 
};

我想在我的MyEngine中继承该类,以便我可以将MyEngine*传递给期望IHandler*的所有人,并让他们能够使用process_input。 但是我不希望允许通过MyEngine*进行访问,因为我不想公开实现细节。

MyEngine* ptr = new MyEngine();
ptr->process_input('a');                           //NOT POSSIBLE
static_cast<IHandler*>(ptr)->process_input('a');   //OK
IHandler* ptr2 = ptr;                              //OK
ptr2->process_input('a');                          //OK

这可以通过受保护的继承和隐式转换来完成吗? 我只是设法得到:

  

从“MyEngine *”转换为“IHandler *”存在,但无法访问

由于我来自C#后台,这基本上是C#中的显式接口实现。 这是C ++中的有效方法吗?

其他

为了更好地了解我为什么要这样做,请考虑以下事项:

TcpConnection实现了TCP上的通信,并且在其构造函数中需要指向接口ITcpEventHandler的指针。 当TcpConnection获取套接字上的某些数据时,它会使用ITcpEventHandler将该数据传递给ITcpEventHandler::incomingData,或者当轮询传出数据时使用ITcpEventHandler::getOutgoingData

我的班级HttpClient使用TcpConnection(聚合)并将自身传递给TcpConnection构造函数,并在这些接口方法中进行处理。

因此TcpConnection必须实施这些方法,但我不希望使用HttpClient的用户直接访问ITcpEventHandler方法incomingData,{{1} })。他们不应该直接致电getOutgoingDataincomingData

希望这能澄清我的用例。

3 个答案:

答案 0 :(得分:5)

使用protected派生会使基类的成员无法通过指向派生类的指针访问,并且不允许隐式转换。

在我看来,你想要的不是禁止通过基类(接口)访问,而是通过派生类(具体实现):

class IHandler
{
public:
   virtual int process_input(char input) = 0;         //pure virtual
   virtual std::string name() { return "IHandler"; }  //simple implementation
};

class MyEngine : public IHandler
//               ^^^^^^
{
protected: // <== Make the functions inaccessible from a pointer
           //     or reference to `MyEngine`.

   virtual int process_input(char input) { return 0; }   //override pure virtual
   using IHandler::name;                                 //use IHandler version
};

这里,在派生类中,您基本上覆盖了process_input函数的可见性,因此客户端只能通过指针或对基类的引用来调用它们。

这样你就不可能做到这一点:

MyEngine* ptr = new MyEngine();
ptr->process_input('a');   // ERROR!
std::cout << ptr->name();  // ERROR!

但这将是可能的:

IHandler* ptr = new MyEngine();
ptr->process_input('a');   // OK
std::cout << ptr->name();  // OK

答案 1 :(得分:1)

在C ++ protectedprivate继承中,可以使用继承实现。也就是说,您定义了一个带有方法的类,例如模板类,当您想要使用它的功能而不是它的接口时,您继承protectedprivate。所以实际上你的基类需要定义你想要在子类中使用的方法。

Here是此主题的链接。我同意,这真的很难。

答案 2 :(得分:1)

有点难以理解你希望在这里实现的真正目标,因为你是否在父或子上调用方法,只要它是虚拟的,就会调用相同的方法。

那说你有几个选择。

您可以通过强制返回接口的create调用来使用户不能获取子类型的指针(或对象)。然后你不必担心人为限制,他们根本就不能生孩子:

class Concrete : public Interface
{
public:
    static Interface* create() { return new Concrete; }

private:
    Concrete() { }
};

您可以将界面覆盖为protected,如另一个答案所示。

您可以利用非虚拟接口模式在父级中定义整个可访问的公共接口。然后它们具有什么对象并不重要,它们总是从接口类获取公共API:

class Interface
{
public:
    void foo() { foo_impl(); }

private:
    virtual void foo_impl() = 0;
};

class Concrete
{
private:
    virtual void foo_impl() { }
};