假设我有纯抽象类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} })。他们不应该直接致电getOutgoingData
或incomingData
。
希望这能澄清我的用例。
答案 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 ++ protected
和private
继承中,可以使用继承实现。也就是说,您定义了一个带有方法的类,例如模板类,当您想要使用它的功能而不是它的接口时,您继承protected
或private
。所以实际上你的基类需要定义你想要在子类中使用的方法。
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() { }
};