让我们假设您有一个状态机的不同状态的基类,该类具有用于不同输入的方法,例如鼠标,键盘,操纵杆等。现在,并不是每个派生状态都将使用所有可能的输入类型。如果基类方法是纯虚拟的,则每个派生状态类都需要始终实现它们中的每一个。为了避免这种情况,我在基类中用空主体声明了它们,并且仅覆盖了特定派生类使用的那些。如果该类不使用某种输入类型,则调用空基类方法get。我将currentState存储在基类指针中,并仅将输入提供给它,而不必知道它实际上是哪个特定的派生状态,以避免不必要的转换。
class Base
{
public:
virtual void keyboardInput() {}
virtual void mouseInput() {}
};
class Derived : public Base
{
public:
void keyboardInput()
{
// do something
}
// Derived doesnt use mouseInput so it doesn't implement it
};
void foo(Base& base)
{
base.keyboardInput();
base.mouseInput();
}
int main()
{
Derived der;
foo(der);
}
这被认为是一种好习惯吗?
答案 0 :(得分:4)
您的问题是基于观点的,但是我宁愿遵循这种方法来使用界面:
struct IBase {
virtual void keyboardInput() = 0;
virtual void mouseInput() = 0;
virtual ~IBase() {}
};
class Base : public IBase {
public:
virtual void keyboardInput() override {}
virtual void mouseInput() override {}
};
class Derived : public Base {
public:
void keyboardInput() override {
// do something
}
// Derived doesnt use mouseInput so it doesn't implement it
};
int main() {
std::unique_ptr<IBase> foo = new Derived();
foo->keyboardInput();
foo->mouseInput();
return 0;
}
一些论点为何在评论中添加了更好的做法:
答案 1 :(得分:2)
这实际上取决于您要从方法中得到什么。声明接口时,通常将这些方法保留为纯虚拟方法,因为必须要求来实现这些方法,才能使类完全起作用。将它们标记为纯虚拟信号“您必须实现这一点。”
但是,有时有些方法可能什么也不做,并且对于所有可能的实现方式都是无效的。这不是很常见,但是有可能。
我认为您的界面不是这种情况,您应该遵循@πάνταῥεῖ的回答。或通过多重继承来做到这一点:
class MouseInput {
public:
virtual void mouseInput() = 0;
}
class KeyboardInput {
public:
virtual void keyboardInput() = 0;
}
class Derived : public KeyboardInput
{
public:
virtual void keyboardInput() override
{
// do something
}
};
class AllInput : public KeyboardInput, public MouseInput
{
public:
virtual void keyboardInput() override
{
// do something
}
virtual void mouseInput() override
{
// do something
}
};
这样做的好处是,您可以拥有明确表示它们可以使用一种输入的方法:
void doSomethingMouseIsh(MouseInput* input);
缺点是,除非您将InterfaceAllInput
作为接口并将其用于所有“所有输入法”,否则将鼠标和键盘输入组合在一起的方法会变得很奇怪。
最后的提示:只要您尝试编写简洁的代码,考虑每个用例比一些最佳实践更重要。
答案 2 :(得分:1)
如果您要对此严格一点的话,这确实违反了ISP(https://en.wikipedia.org/wiki/Interface_segregation_principle),因为您迫使子类依赖于它不使用的方法-但是通常,如果替代方法添加了它,在实践中还不错更加复杂。