我遇到了以下设计问题:
我正在为应用程序使用Qt C ++库。在这个库中有“模型”类,它们都继承自QAbstractItemModel
(如QAbstractTableModel
,QStandardItemModel
等)。我想继承其中几个类,但是要定义我们自己必须共享的接口。
我目前正在这样做的方法是定义一个接口(纯虚拟类)并让继承类继承这个。举个例子,假设我希望一个类继承QAbstractTableModel
以获得doSomething
函数:
class MyInterface {
public:
virtual void doSomething() = 0;
}
class MyModel : public QAbstractTableModel, public MyInterface {
...
}
但是,我只想将对象作为QAbstractItemModel
传递。要使用接口类,我必须将它们转换为MyInterface
个对象,然后调用这些函数,这会导致遍布整个地方。此外,如果其他任何人让他们自己的类从QAbstractItemModel
进入,那么如果他们不继承该接口,那么似乎还有出错的地方。
我可以使用更好的设计来完成所有这些吗?
答案 0 :(得分:0)
是。首先,根本不要使用MyInterface类。当您想要获取具有doSomething()方法的任何对象时,请使用模板。如果您“将对象作为QAbstractModel传递”,这意味着您正在编写接受QAbstractModel类型的任何对象的函数,其中一些可能不是MyModel(甚至是MyInterface)。如果你打电话给doSomething,那么你违反了该函数接受QAbstractModel类型的任何对象的合同。
答案 1 :(得分:0)
您使用的是哪种铸件?如果你使用dynamic_cast,你的代码看起来不会更好但是如果你总是检查转换的null结果,你应该至少可以使用非接口类的错误。
当有大量可能的类(如MyModel,因为你无法从QAbstractTableModel直接转换(动态或静态))到MyInterface时,这会变得更复杂 - 你需要尝试向它们全部转换才能向下转换为接口类稍后的。一种解决方案可能是使用一些模板技巧 -
class MyInterface {
public:
virtual void doSomething() = 0;
}
template <typename T>
class MyTemplatedInterface: public T, public MyInterface {
private:
virtual void foo(){}; // might be neceseary to be able to dynamic_cast to this type
}
class MyModel: public MyTemplatedInterface<QAbstractTableModel>{
public:
virtual void doSomething(){};
}
这样,如果你得到QAbstractTableModel指针并想知道它是否实现了MyInterface,你只需要转换为MyTemplatedInterface,无论实际的基本实现类型是什么。这个设计有几个缺点,比如无法处理多个接口或声明模板化类的构造函数 - 它们中的大多数将在c ++ 0x中删除,但此时没有编译器实现足够的代码来编写代码,具体取决于它