Наследование библиотечного класса при определении пользовательского интерфейса - PullRequest
1 голос
/ 16 сентября 2011

Я сталкиваюсь со следующей проблемой проектирования:

Я использую библиотеку Qt C ++ для приложения.В этой библиотеке есть «модельные» классы, которые все наследуются от QAbstractItemModel (например, QAbstractTableModel, QStandardItemModel и т. Д.).Я хочу наследовать от нескольких из этих классов, но определяю свой собственный интерфейс, который они должны совместно использовать.

В настоящее время я делаю это, определяя интерфейс (чисто виртуальный класс) и получая наследуемые классы отэто тоже.В качестве примера, скажем, я хочу, чтобы класс, унаследованный от QAbstractTableModel, имел функцию doSomething:

class MyInterface {
public:
    virtual void doSomething() = 0;
}
class MyModel : public QAbstractTableModel, public MyInterface {
    ...
}

Однако я просто хочу передать объекты как QAbstractItemModel.Чтобы использовать интерфейсные классы, я должен привести их к MyInterface объектам, а затем вызвать функции, что приводит к приведению повсюду.Кроме того, если кто-то еще делает свой собственный класс наследующим от QAbstractItemModel, создается впечатление, что есть место для ошибки, если он также не наследует интерфейс.

Есть ли лучший дизайн, который я мог бы использовать, чтобы выполнить все это

Ответы [ 2 ]

0 голосов
/ 16 сентября 2011

Какой тип кастинга вы используете? если вы используете dynamic_cast, ваш код не будет выглядеть лучше, но если вы всегда будете проверять нулевой результат приведения, вы должны по крайней мере быть в порядке с возможными ошибками с неинтерфейсными классами.

Это становится более сложным, когда существует большой набор возможных классов, таких как 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, но на данный момент ни один компилятор не реализует его достаточно для написания кода в зависимости от него. .

0 голосов
/ 16 сентября 2011

Да.Во-первых, вообще не используйте класс MyInterface.Используйте шаблоны для случаев, когда вы хотите получить любой объект, у которого есть метод doSomething ().Если вы «передаете объект как QAbstractModel», это означает, что вы пишете функции, которые принимают любой объект типа QAbstractModel, некоторые из которых могут не принадлежать MyModel (или даже MyInterface).Если вы делаете вызов doSomething, то вы нарушаете договор о том, что функция принимает любой объект типа QAbstractModel.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...