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

omi*_*nes 2 c++ inheritance abstract-class casting 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 */ } 
};
Run Code Online (Sandbox Code Playgroud)

我希望在我的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
Run Code Online (Sandbox Code Playgroud)

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

从"MyEngine*"到"IHandler*"的转换存在,但无法访问

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

额外:

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

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

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

所以TcpConnection必须实现这些方法,但我不希望用户使用HttpClient直接访问ITcpEventHandler方法(incomingData,getOutgoingData).他们不应该打电话incomingDatagetOutgoingData直接打电话.

希望这能澄清我的用例.

And*_*owl 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
};
Run Code Online (Sandbox Code Playgroud)

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

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

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

但这将是可能的:

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