Недавно меня озадачили вопросом: чем отличается абстрактный класс от интерфейса в С++? Я вроде бы не настолько забыл С++, что бы помнить об абстрактных классах, но не помнить об интерфейсах.
В С++ есть понятие абстрактного класса - класс, у которого есть хотя бы одна чисто виртуальная функция и, соответственно, нельзя создать объект этого класса. Иногда еще говорят о чисто абстрактных классах, у которых все функции чисто виртуальные, но это скорее искусственное понятие, в большинстве случаев ничем не отличающееся от просто абстрактных классов.
Ни о каких интерфейсах в стандарте С++ не говориться, кроме того, что абстрактный класс может предоставлять интерфейс, который реализуется наследниками (10.4.1):An abstract class can also be used to define an interface for which derived classes provide a variety of implementations.
Все остальное - это проблемы семантики. Например, в пределах команды (компании), можно принять, что чисто абстрактные классы - это классы, у которых все функции чисто абстрактные, а чисто абстрактные классы, у которых нет не-константных членов данных и все функции public - это интерфейсы. Или под интерфейсами могут подразумеваться просто абстрактные классы и даже COM-интерфейсы.
Лично я придерживаюсь мнения, что интерфейс - это любой класс, у которого есть хотя бы одна виртуальная функция. Клиенту, который ориентируется на этот интерфейс используя указатель на базовый класс, по барабану, есть ли у базового класса члены данных и если у него не чисто виртуальные функции. Кроме того, с позиции клиента, все доступные методы объекта - это интерфейс, даже если объект описывается классом без виртуальных функций.
Так что ответить о разнице между абстрактными классами и интерфейсом в С++ не так просто, так как может быть несколько правильных точек зрения. Кроме того, возможно путаются понятия ОО концепции и реализации этой концепции в конкретном языке программирования. А может, спрашивающий джавист...
Рекомендую к прочтению: Доступность действия в любой момент - оправдание не делать его вообще, Эффект осознания, Парадоксальные заповеди
суббота, 25 октября 2008 г.
Абстрактный класс VS интерфейс
Автор:
sash_ko
на
12:47
1 коммент.
Ярлыки: Программизм, C++
четверг, 16 октября 2008 г.
Windows исключения
Интересное описание устройства исключений в Windows (не тех, которые C++-исключения): А что, собственно, происходит, когда бросается исключение?
Автор:
sash_ko
на
21:59
0
коммент.
Ярлыки: Программизм
PyQt in-depth: типы signal-slot соединений
В Qt слоты и сигналы являются платформенно-независимым средством обмена сообщениями между объектами. Подробнее писать о них я не собираюсь, так это хорошо сделали до меня прямо в документации Qt или, например, вот здесь. Я хочу выделить некоторые особенности их использования, с которыми мне удалось столкнуться.
Signal-slot механизм - это не просто вызов колбеков в чистом виде. Между сигналом и слотом устанавливается соединение, которое может быть 4-х типов:
- DirectConnection - прямое соединение, когда сигнал моментально обрабатывается слотом;
- QueuedConnection - сигнал добавляется в очередь и ожидает своего "выхода" в очереди сообщений, при этом поток, в котором возник сигнал не блокируется;
- BlockingQueuedConnection - то же, что и QueuedConnection, но вызывающий поток блокируется, пока сигнал не будет обработан;
- AutoConnection - автоматически выбирается DirectConnection, если сигнал вызывается из того же потока, в котором живет приемник, и QueuedConnection, если используются разные потоки.
Как видно, два соединения являются синхронными, одно асинхронным и одно автоматически выбирает себе соответствующий тип в зависимости от внешнего окружения.
Тип соединения указывается как параметр QObject.connect:
QObject.connect(doer, SIGNAL('event'), self.handle, Qt.DirectConnection)
Теперь, как это все работает на примере. Пусть есть задача, которую надо выполнить в отдельном потоке (класс Doer) и обработчик, который должен узнать о результате выполнения (класс Handler).
На это примере можно проследить где и когда будет отрабатываться слот в зависимости типа соединения.
В случае DirectConnection, сигнал обрабатывается синхронно, в потоке, где выполнялась задача:
task in thread < Thread(Thread-1, started) >
handle in thread < Thread(Thread-1, started) >
handle finish
after notify
При QueuedConnection, сигнал обрабатывается асинхронно в главном потоке приложения:
task in thread < Thread(Thread-1, started) >
after notify
handle in thread < _MainThread(MainThread, started) >
handle finish
BlockingQueuedConnection заставляет поток, вызывающий сигнал, ждать обработки, которая происходит в главном потоке приложения:
task in thread < Thread(Thread-1, started) >
handle in thread < _MainThread(MainThread, started) >
handle finish
after notify
При AutoConnection ситуация такая же как и при QueuedConnection, так как сигнал и приемник в разных потоках:
task in thread < Thread(Thread-1, started) >
after notify
handle in thread <_MainThread(MainThread, started)>
handle finish
Но если изменить одну строчку кода результат будет таким же как при DirectConnection:
task in thread <_MainThread(MainThread, started)>
handle in thread <_MainThread(MainThread, started)>
handle finish
after notify
Тип соединения BlockingQueuedConnection стоит использовать только в многопоточных приложениях, так как в одном потоке может привести к dead lock'у, о чем Qt должно предупредить ворнингом:
Qt: Dead lock detected while activating a BlockingQueuedConnection
Таким образом, Qt позволяет гибко настраивать обработку сигналов в синхронном и асинхронном режиме, в одном или нескольких потоках.
Автор:
sash_ko
на
11:19
2
коммент.
Ярлыки: Программизм, python, Qt
среда, 15 октября 2008 г.
Неосторожность с lambda
Все утро боролся с кодом, в котором вроде как все правильно, но работал не так как надо. Выглядел он примерно так:
Но результат выполнения этого кода получился неожиданный:
item a result c
item c result c
item b result c
Проблема оказалась в строке:
m.addAction(item, lambda : item)
lambda использует переменную item из контекста вызывающей функции. Переменная изменяется в цикле и к моменту вызова lambda в item сохраняется значение последней итерации.
Отсюда вывод - смешивание функционального подхода и "обычного" может привести к самым неожиданным результатам. Для того, что бы избежать такого смешивания, достаточно заменить цикл на map:
map(lambda item: m.addAction(item, lambda : item), lst)
Автор:
sash_ko
на
12:28
8
коммент.
Ярлыки: python
воскресенье, 28 сентября 2008 г.
Отзыв об Exception #09
Скажу сразу, что 9-тый Exception понравился мне намного больше, чем 7-й (на 8-м я не был). Причин тому несколько: темы были не "узконаправленные", что показало, что python - не только для веба; выступлений было не много - один мастер класс и два небольших доклада; Open Space показал себя как отличный способ для неформального обмена опытом.
Первым выступал Сергей Щетинин с мастер-классом "Trellis. Приложения основанные на обработке сообщений". Только ради того, что бы узнать о Trellis, стоило пойти на этот семинар. Для меня, фанатеющего от event-driven architecture - это было то, чего мне так давно не хватало: полностью автоматизированный обмен и обработка событий (без использования колбеков) и изолированность вычислений от сторонних эффектов. Это идеально подходит для создания GUI, когда многие виджеты зависят от многих данных.
Trellis позволяет создавать компоненты, у которых автоматически отслеживаются изменения атрибутов (созданных при помощи attr()), при использовании этих атрибутов в зависимостях (зависимости - декорированные функции, использующие эти атрибуты):
На первый взгляд, Trellis является настолько мощным механизмом, что его даже страшно использовать, не разобравшись основательно (а вдруг я слишком преувеличил его значение). Но все же у меня сложилось впечатление, что это именно то, чего мне всегда не хватало.
Второй доклад Дмитрия Кожевина о диванном программировании (а позже и обсуждение на Open Space - "Думать как гений"), так же затронул актуальную для меня тему эффективной организации рабочего процесса и самоорганизации. Причем выступление Дмитрия (как и на прошлом семинаре) не только интересное, но и вдохновляет воплотить в жизнь все услышанное.
Последний небольшой доклад делал Максим Ищенко об автоматизации управления несколькими серверами при помощи питоновской тулзы Fabric.
Во-общем, на этом семинаре я почерпнул достаточное количество полезной информации, информации для размышления и вдохновился на работу над собой
Автор:
sash_ko
на
12:25
0
коммент.
среда, 13 августа 2008 г.
понедельник, 11 августа 2008 г.
default параметр в getattr
В примере увидел интересный способ использования getattr. Третий необязательный параметр функции (getattr( object, name[, default])) - значение, которое будет возвращено, если атрибута с указанным именем не существует. Если использовать лямбду, которая делает "ничего" - lambda : None, то во многих случаях можно отказаться от использования дополнительной функции hasattr:
Автор:
sash_ko
на
10:51
0
коммент.
Ярлыки: Программизм, python