Что является источником данных запроса 1с
Структура кода запроса в 1С легко изучить. Начнем от простого запроса к более сложным вариантам.
Выбрать
Любой запрос имеет команду ВЫБРАТЬ, после которой могут идти дополнительные параметры выборки, которые позднее рассмотрим отдельно:
ПЕРВЫЕ
РАЗЛИЧНЫЕ
РАЗРЕШЕННЫЕ
Далее идет список полей выборки.
Простейший запрос в 1С может иметь такой вид:
Данный запрос вернет таблицу, состоящую из одной строки и одной колонки, в которой будет числовое значение равное 1.
Усложняем запрос: добавим еще поля, разделив их запятой
ВЫБРАТЬ 1, 2, "3"
Этот запрос также вернет 1 строку, но уже с 3 колонками, две из которых содержат числа, а 3 строковое.
Система 1С автоматически присвоит этим полям имена «Поле1», «Поле2», «Поле3», что неплохо, но не всегда удобно, ведь полей может быть значительно больше.
Поэтому в языке запросов существует специальный оператор именования КАК , который идет после поля,
Предыдущий запрос можно представить в таком виде:
ВЫБРАТЬ 1 КАК Один, 2 КАК Два, "3" КАК ЦифраТриСтрокой
Имена полей задаются по правилам именования переменных: не могут начинаться со строки, содержать пробелы, не должны повторятся в одной выборке, а также отсутствовать (они поставятся автоматически).
Возможно опускать слово КАК, но лучше такой вариант не использовать, так как конструктор запросов это исправит:
ВЫБРАТЬ ссылка ссылка ИЗ Справочник.ФизическиеЛица
Такие простые запросы конечно имеют место в реальных условиях, как вспомогательные таблицы, но обычно требуется выборка из какого-то источника.
Для этого существует оператор ИЗ , в которой источник данных может быть реальной таблицей из базы данных, а также виртуальными таблицами, которые существуют к некоторым таким таблицами или же к временным таблицам.
Пример простого запроса к реальной таблице справочника:
ВЫБРАТЬ ссылка ИЗ Справочник.Контрагенты
В таких запросах мы можем указать конкретные поля, которые нам нужны или указать *.
ВЫБРАТЬ * ИЗ Справочник.Контрагенты
Такой вариант универсальный, но избыточное количество полей замедляет и усложняет их разбор позднее.
Вложенные таблицы
Также возможно обращение к вложенной таблице:
ВЫБРАТЬ * ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КонтактнаяИнформация
Как видите, здесь мы впервые использовали именование таблицы, которое также упрощает работу при написании запроса, это дает возможность обращения по этому имени к полям:
ВЫБРАТЬ КИ.Ссылка ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КИ //так иногда будет короче
Особенностью запросов к вложенным таблицам является то, что возможно обращение к родительской таблице через поле ссылка через точку.
ВЫБРАТЬ Ссылка.Наименование ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КонтактнаяИнформация
Подобная возможность используется и при обращении к реквизитам ссылочных полей: система сама неявно соединит нужные таблицы, но использование такого обращения следует использовать реже (особенно при указании условий в виртуальных таблицах или условий соединения таблиц).
ВЫБРАТЬ Ссылка, ОсновнойДоговор.Наименование КАК НазваниеДоговора ИЗ Справочник.Контрагенты
В данном случае поле ОсновнойДоговор может быть пустым, тогда обращение к его наименованию не вызовет ошибку, но значение будет NULL, поэтому рекомендуется использовать ЕстьNULL.
Дополнительно
Вернемся к запросу
ВЫБРАТЬ КИ.Ссылка ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КИ
В данном запросе, мы не выбираем поля из самой подтаблицы КонтактнаяИнформация, и в случае если в ней несколько строк, то в выборку попадут несколько строк с одинаковым содержимым.
Чтобы избежать этого можно воспользоваться служебным словом РАЗЛИЧНЫЕ: система устранит все дубли автоматически.
ВЫБРАТЬ РАЗЛИЧНЫЕ КИ.Ссылка ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КИ
Если мы хотим ограничить результат выборки количеством записей (например сотней) используем ПЕРВЫЕ, но использовать ее необходимо с осторожностью (иногда эта команда срабатывает раньше, чем применяются условия запросов), следует тестировать запросы основательно.
ВЫБРАТЬ ПЕРВЫЕ 100 КИ.Ссылка ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КИ
Последнее, что следует упомянуть при изучении основ выборки запросов 1С:
Команду «ПОМЕСТИТЬ », позволяющую помещать выборку в таблицу для многократного последующего использования.
Источник может также выборкой из запроса, указанной в скобках:
ВЫБРАТЬ * ИЗ (ВЫБРАТЬ * ИЗ Справочник.Контрагенты) КАК ВложеннаяТаблица
Использование вложенных запросов имеет смысл в случае, если в нем данные как-либо предварительно обрабатываются, а не как в вышеуказанном примере, где это излишне.
В целом, использование временных таблиц и вложенных запросов замедляет выборку, но парадокс в том, что их использование может дать нужный сигнал оптимизатору запросов и эффект получается положительный.
При больших исходных данных, следует проверять оба варианта использования, на предмет скорости исполнения, для принятия окончательного варианта запроса.
Регистр команд, имен и полей запроса не имеет значение: Выбрать и ВыБРатЬ равносильны.
Если новая модель не удалась, позаботься о рекламе изделия.
— Артур Блох
Цель лекции: научиться создавать внешние обработки , изучить основные сведения о запросах .
7.1. Основные сведения о запросах
Одна из функций учетной системы - предоставление пользователям различной информации. Как правило, делается это с помощью отчетов. Например, в нашем случае вполне логично было бы иметь отчет, который выводит информацию о поступивших и выбывших материалах по отдельным материально-ответственным лицам (а может быть и по всей организации в целом), а так же - об остатках материалов. Подобная функциональность - то есть - выборка данных, осуществляется в 1С:Предприятии с помощью запросов .
Поэтому, прежде чем говорить об отчетах, да и прежде чем продолжать изложение дальнейших тем, нам необходимо познакомиться с запросами .
Запросы создают с некоторой целью. Например, она может звучать так: "Узнать количество и стоимость материалов, числящихся за Ивановым И.И.". После того, как цель запроса сформулирована, нужно выполнить определенные шаги, которые позволяют получить нужную информацию:
- Подобрать подходящие источники данных для запроса ;
- Составить текст запроса - либо вручную, либо пользуясь конструктором запросов ;
- Выполнить запрос ;
- Обработать результаты запроса .
Прежде чем переходить к практической работе с запросами , обсудим общие положения, важные для дальнейшего понимания материала.
Источники данных для запросов
При работе с запросами возникает такое понятие, как источник данных для запроса . То есть - те места, откуда запрос будет брать данные. Источники данных делятся на две группы. Первая - это так называемые реальные таблицы . Вторая - виртуальные .
Реальные таблицы называются так потому, что они физически хранятся в базе данных. Реальные таблицы , в свою очередь, подразделяются на объектные (ссылочные) и необъектные (не ссылочные).
В объектных таблицах хранятся данные объектов системы, то есть - ссылочных типов данных . Это - документы, справочники. Эти таблицы имеют поле Ссылка, которое содержит ссылку на объект, данные которого представлены в таблице.
В необъектных таблицах хранятся данные других типов - например - записи регистров.
Виртуальные таблицы , в отличие от реальных , нигде специально не хранятся. Система "собирает" эти таблицы из реальных данных, используя одну или несколько реальных таблиц . При создании виртуальных таблиц их можно параметризовать - то есть - задать параметры, которые ограничивают отбор данных в эти таблицы. Если вы пользуетесь виртуальными таблицами (а без них вы вряд ли сможете обойтись, как вы увидите позже), и вам нужно, чтобы они включали в себя данные, ограниченные некоторым отбором, нужно выполнять этот отбор, используя параметры виртуальных таблиц . Есть и другие способы выбора из виртуальных таблиц нужных данных, но они уступают в скорости работы параметризации этих таблиц.
Поля таблицы могут содержать либо какие-то данные, либо - вложенные таблицы . Причем, поле таблицы может иметь какой-то один тип, либо - составной тип данных. Однако, если поле хранит данные, они всегда какого-то одного типа.
Перед созданием запроса , или в процессе создания, нужно определиться с источниками данных для него. После того, как источники данных определены, следует написать текст запроса .
Написание текста запроса
Во встроенном языке системы есть объект Запрос. Именно он используется для работы с запросами . Особенности получения данных определяет текст запроса . Этот текст можно либо написать вручную, используя конструкции языка, либо воспользоваться так называемым конструктором запросов . Конструктор запросов позволяет в наглядном виде настроить запрос , однако, его результатом является точно такой же текст, который пишут вручную. В запрос можно передавать параметры, делать это нужно до выполнения запроса .
Выполнение запроса и обработка результатов запроса
После того, как создан текст запроса и в запрос переданы параметры, запрос выполняют. Результат выполнения запроса выглядит в виде таблицы, содержащей запрошенные данные. Эту таблицу необходимо обработать и применить полученные данные по назначению - вывести их в отчет, использовать для проверки каких-либо ограничений и так далее.
Для того, чтобы начать практическую работу с запросами , мы немного отвлечемся от, собственно, запросов , и создадим небольшую внешнюю обработку , которая позволит нам в максимально наглядном виде освоить основы работы с запросами .
7.2. Создание внешней обработки КонсольЗапросов
Внешние отчеты и обработки удобно использовать для того, чтобы выполнять предусматриваемые ими действия в различных системах. Так же внешние отчеты и обработки обычно используют для того, чтобы добавить в существующую конфигурацию какие-то новые возможности, настроить ее под нужды клиента, но при этом не изменять основную конфигурацию .
Войдем в Конфигуратор и выполним команду Файл > Новый > Внешняя обработка, рис. 7.1.
Введем в поле имя КонсольЗапросов, для начала редактирования формы обработки нажмем на кнопку Открыть в поле Основная форма внешней обработки. Появится окно Конструктор формы обработки, оставим в нем все по умолчанию и нажмем Готово.
Добавим в форму элемент управления Поле текстового документа, зададим ему имя ТекстЗапроса, установим в параметре Расширение значение Язык запросов. Добавим в список реквизитов формы новый реквизит , зададим ему имя ТекстЗапросов и тип Строка.
Это позволит использовать в данном поле , при работе в режиме 1С:Предприятие, конструктор запросов , синтаксические конструкции языка запросов будут автоматически выделяться, рис. 7.2.
Поле ТекстЗапроса будет содержать текст запроса , который мы можем либо написать вручную, либо создать, воспользовавшись конструктором запроса .
Теперь добавим в форму еще один элемент управления - табличное поле . Зададим ему имя - РезультатВыполненияЗапроса. Так же добавим в форму поясняющие надписи: " Введите текст запроса " и " Результат выполнения запроса ", рис. 7.3.
В табличное поле мы будем помещать результат выполнения запроса .
Теперь зададим обработчик нажатия кнопки Выполнить. Для этого откроем окно свойств кнопки и нажмем на кнопку Открыть в поле Действие. Процедура обработчика события нажатия на кнопку будет выглядеть следующим образом:
Поясним ее команды. Они, в основном, связаны с новым для вас объектом Запрос.
Создаем новый объект типа Запрос, записываем ссылку на него в переменную Запрос .
Записываем в свойство запроса Текст данные, которые хранятся в поле текстового документа.
Помещаем в поле табличного документа РезультатВыполненияЗапроса результат выполнения запроса . Этот результат получается, во-первых, после использования метода запроса Выполнить() . Этот метод выполняет запрос , если запрос выбрал какие-то данные из базы, возвращаемое значение имеет тип РезультатЗапроса. Метод Выгрузить() выгружает результат запроса в таблицу значений, которая и попадает в поле табличного документа РезультатВыполненияЗапроса.
Благодаря этой команде в поле РезультатВыполненияЗапроса можно увидеть его содержимое, иначе оно будет выглядеть пустым.
После того, как создание обработки завершено, сохраним ее командой главного меню программы Файл > Сохранить.
Файлы внешних обработок имеют расширение *.EPF, рис. 7.4.
Запустим систему в режиме 1С:Предприятие. Для того, чтобы работать с внешней обработкой , нам сначала нужно открыть ее. Для этого воспользуемся командой главного меню программы Файл > Открыть и с помощью стандартного окна открытия файлов выберем интересующую нас обработку , рис. 7.5.
Этой статьей мы начинаем цикл, посвященный работе с запросами в системе 1С:Предприятие версии 8.1 и выше.
Запрос — это мощнейший инструмент, служащий для быстрого (по сравнению со всеми другими способами) получения и обработки данных, содержащихся в различных объектах информационной базы 1С.
Создание запроса
Запрос создается как отдельный объект, который имеет обязательный атрибут Текст, куда собственно и помещается сам запрос. Кроме этого, в запрос могут быть переданы различные параметры, необходимые для его выполнения. После того, как текст и параметры запроса заполнены, запрос необходимо выполнить и поместить результат выполнения в выборку или таблицу значений. Выглядит это все примерно так:
//Создаем запрос
Запрос = новый Запрос ;
//Заполняем текст запроса
Запрос . Текст = "Тут пишем текст запроса" ;
//Передаем в запрос параметры
Запрос . УстановитьПараметр ( "ИмяПараметра" , ЗначениеПараметра ) ;
//Выполняем запрос
Результат = Запрос . Выполнить ( ) ;
//Выгружаем результат запроса в выборку
Выборка = Результат . Выбрать ( ) ;
//Выгружаем результат запроса в таблицу значений
Таблица = Результат . Выгрузить ( ) ;
//Последние действия можно объединить
Выборка = Запрос . Выполнить ( ) . Выбрать ( ) ;
//или
Таблица = Запрос . Выполнить ( ) . Выгрузить ( ) ;
Основы языка запросов 1С
Простейшие и наиболее часто применяемые запросы служат для получения данных из какого-то источника. Источником могут являться практически все объекты, содержащие какие-либо данные: справочники, документы, регистры, константы, перечисления, планы видов характеристик и т.д.
Из этих объектов с помощью запроса можно получать значения реквизитов, табличных частей, реквизитов табличных частей, изменений, ресурсов и т.д.
Для получения текста запроса часто бывает удобно пользоваться Конструктором запроса. Он вызывается при щелчке правой кнопкой в любом месте программного модуля.
Например, если необходимо получить значения всех реквизитов справочника Контрагенты, то запрос будет выглядеть так:
Если же нужно получить только отдельные реквизиты, то — так:
Для получения такого текста запроса в Конструкторе запроса нужно выбрать соответствующие поля на вкладке Таблицы и поля.
Выбираемым в запросе элементам и источникам можно присваивать псевдонимы и использовать их в дальнейшем как в самом запросе, так и при работе с результатом. Кроме того, в запросе могут присутствовать поля с заранее определенным конкретным значением, или с рассчитываемым значением:
Запрос . Текст = "ВЫБРАТЬ
| Клиенты.Код КАК Номер,
| Клиенты.Наименование КАК Имя,
| 1000 КАК ПолеСоЗначением
|ИЗ
| Справочник.Контрагенты КАК Клиенты" ;
Выборка = Запрос . Выполнить ( ) . Выбрать ( ) ;
Пока Выборка . Следующий ( ) Цикл
НомерКлиента = Выборка . Номер ;
ИмяКлиента = Выборка . Имя ;
Знач = Выборка . ПолеСоЗначением ;
КонецЦикла ;
Для задания псевдонимов служит вкладка Объединения/Псевдонимы в Конструкторе запросов.
А поле с фиксированным или рассчитываемым значением создается вручную на вкладке Таблицы и поля, в колонке Поля.
Все выбранные элементы можно упорядочивать как в прямом, так и в обратном порядке. При этом можно выбирать один или несколько полей для упорядочивания. Вместе с упорядочиванием иногда бывает полезно выбрать только один или несколько первых элементов.
//Упорядочим клиентов по имени от А до Я и выберем первых 10
Запрос . Текст = "ВЫБРАТЬ ПЕРВЫЕ 10
| Клиенты.Код КАК Номер,
| Клиенты.Наименование КАК Имя,
| 1000 КАК ПолеСоЗначением
|ИЗ
| Справочник.Контрагенты КАК Клиенты
|УПОРЯДОЧИТЬ ПО
| Имя" ;
//Выберем самого последнего по алфавиту клиента
Запрос . Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
| Клиенты.Код КАК Номер,
| Клиенты.Наименование КАК Имя,
| 1000 КАК ПолеСоЗначением
|ИЗ
| Справочник.Контрагенты КАК Клиенты
|УПОРЯДОЧИТЬ ПО
| Имя УБЫВ" ;
Можно ограничить выборку элементов теми, на которые пользователь имеет права доступа. Или убрать из результата запроса повторяющиеся строки.
//Выборка разрешенных пользователю данных
Запрос . Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Клиенты.Код КАК Номер,
| Клиенты.Наименование КАК Имя,
| 1000 КАК ПолеСоЗначением
|ИЗ
| Справочник.Контрагенты КАК Клиенты" ;
//Выборка неповторяющихся элементов
Запрос . Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ
| Клиенты.Код КАК Номер,
| Клиенты.Наименование КАК Имя,
| 1000 КАК ПолеСоЗначением
|ИЗ
| Справочник.Контрагенты КАК Клиенты" ;
Порядок задается на вкладке Порядок в Конструкторе запросов, количество выбираемых элементов, параметры разрешенности и повторяемости — на вкладке Дополнительно.
Продолжение следует…
Добавить комментарий Отменить ответ
Теперь мы в соцсетях! Подписывайтесь, чтобы получать информацию о последних обновлениях или задать вопрос.
Не очень часто, но приходится делать запросы к таблице значений в 1С. При этом нужно учитывать несколько нюансов.
Во-первых, в таблице значений, являющейся источником данных для запроса, колонки должны быть типизированы.
ТаблицаОплат = новый ТаблицаЗначений ;
ТаблицаОплат . Колонки . Добавить ( "Дата" , Новый ОписаниеТипов ( "Дата" .
Новый Квалификаторыдаты ( ЧастиДаты . Дата ) ) ) ;
ТаблицаОплат . Колонки . Добавить ( "Договор" , Новый ОписаниеТипов ( "ДокументСсылка.ДоговорЗайма" ) ) ;
ТаблицаОплат . Колонки . Добавить ( "Сумма" , Новый ОписаниеТипов ( "Число" .
Новый КвалификаторыЧисла ( 15 , 2 ) ) ) ;
Подробнее вопрос типизации колонок рассмотрим в следующей статье, посвященной работе с таблицами значений.
Во-вторых, таблица значений передается в запрос как обычный параметр. Имена выбираемых полей соответствуют именам колонок таблицы. Но запрос придется писать вручную, конструктор запроса в данном случае не поможет.
запрос = новый запрос ;
запрос . Текст = "ВЫБРАТЬ
| Оплаты.Дата,
| Оплаты.ДоговорЗайма,
| Оплаты.Сумма КАК ОПЛАТА,
| Оплаты.Просрочка
|ПОМЕСТИТЬ Оплаты
|ИЗ
| &ТаблицаОплат КАК Оплаты" ;
Запрос . УстановитьПараметр ( "ТаблицаОплат" , ТаблицаОплат ) ;
В-третьих, результат выполнения запроса к таблице значений нельзя использовать сразу. Его нужно поместить во временную таблицу, сделать запрос к ней и только потом делать выборку из результата. Это можно реализовать двумя способами:
-
Создать пакетный запрос.
запрос = новый запрос ;
запрос . Текст = "ВЫБРАТЬ
| Оплаты.Дата,
| Оплаты.ДоговорЗайма,
| Оплаты.Сумма КАК ОПЛАТА,
| Оплаты.Просрочка
|ПОМЕСТИТЬ Оплаты
|ИЗ
| &ТаблицаОплат КАК Оплаты
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Оплаты.Дата КАК Дата,
| Оплаты.ДоговорЗайма КАК ДоговорЗайма,
| Оплаты.ОПЛАТА КАК ОПЛАТА,
| Оплаты.Просрочка КАК Просрочка
|ИЗ
| Оплаты КАК Оплаты" ;
запрос = новый запрос ;
Запрос . МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц ;
запрос . Текст = "ВЫБРАТЬ
| Оплаты.Дата,
| Оплаты.ДоговорЗайма,
| Оплаты.Сумма КАК ОПЛАТА,
| Оплаты.Просрочка
|ПОМЕСТИТЬ Оплаты
|ИЗ
| &ТаблицаОплат КАК Оплаты" ;
Запрос . УстановитьПараметр ( "ТаблицаОплат" , ТаблицаОплат ) ;
Запрос . Выполнить ( ) ;
запрос . Текст = " |ВЫБРАТЬ
| Оплаты.Дата КАК Дата,
| Оплаты.ДоговорЗайма КАК ДоговорЗайма,
| Оплаты.ОПЛАТА КАК ОПЛАТА,
| Оплаты.Просрочка КАК Просрочка
|ИЗ
| Оплаты КАК Оплаты" ;
Выборка = Запрос . Выполнить ( ) . Выбрать ( ) ;
Добавить комментарий Отменить ответ
Теперь мы в соцсетях! Подписывайтесь, чтобы получать информацию о последних обновлениях или задать вопрос.
Урок 1 - Роль и место запросов в системе 1С Предприятие
В системе 1С Предприятие 8 существует две модели представления данных: объектная и табличная. Типичный метод использования объектной модели выглядит примерно так:
То же действие, но с обращением к табличной модели:
Таким образом, у обеих моделей есть свои достоинства и свои недостатки. Объектная модель хороша, прежде всего, тем, что она чрезвычайно лаконична: если поступиться «читабельностью», простейшие выборки можно получать всего одной строкой кода! Табличная модель значительно уступает по данному критерию объектной, зато имеет ряд неоспоримых преимуществ.
Табличная модель обеспечивает:
- Гибкость: получение сложно-организованных выборок, использование сложных условий, управление блокировками;
- Использование конструктора: повышение скорости написания запроса, уменьшение вероятности появления синтаксических и логических ошибок.
Урок 1 - Конструктор запросов 1C
Одним из самых мощных инструментов 1С Предприятия, без сомнения, является конструктор запросов. Конструктор является визуальным средством для работы с запросами. Поэтому знакомиться с ним мы будем тоже наглядно, с помощью иллюстраций.
Сразу оговоримся, что поместить главу о конструкторе в самом начале курса - решение неоднозначное. Если развивать тему использования запросов строго последовательно, знакомиться с конструктором следовало бы в самом конце, после того, как будут изучены все остальные свойства запросов. Но дело в том, что большую часть запросов мы будем «собирать» именно с помощью конструктора. В этом случае, проблема похожа на извечный вопрос: что было раньше, яйцо или курица? Всё-таки, мы решили начать с конструктора.
Изучать устройство конструктора мы будем на примере универсальной обработки Консоль запросов. Эта обработка входит в состав типовых конфигураций 1С, поэтому её так же вполне можно назвать типовым инструментом.
Урок 3 - Источники данных 1С
Все объекты базы данных 1С (справочники, документы, регистры и т, д.) имеют своё табличное представление, и это вполне объяснимо. В самом деле, физически, вся информация хранится в базе данных в виде плоских таблиц. Никак иначе быть не может, потому что такова природа реляционных баз данных. Следовательно, если предоставить разработчику прикладного решения доступ напрямую (ну, или, почти напрямую) к таблицам, никакого нарушения логики работы с данными не случиться. Более того, поскольку в данном случае мы работаем непосредственно с таблицами, в качестве полезного побочного эффекта можно ожидать повышения быстродействия в сравнении с объектной моделью.
Теперь, когда мы определились с тем, что же такое табличная модель данных 1С:Предприятия пора рассмотреть ещё одно понятие, непосредственно с нею связанное. Речь идёт о виртуальных таблицах. Кроме таблиц, действительно существующих в базе, о которых мы говорили до сих пор, (они так и называются, Реальными) в системе вводится понятие Виртуальных таблиц. Физически, никаких новых мистических таблиц в базе, конечно же, нет. Просто обращение к виртуальной таблице автоматически преобразуется механизмом запросов в обращение к таблице реальной. Алгоритм преобразования может весьма изощренным, но нам (разработчикам) это никаких особых хлопот не доставляет. Нам важно то, что виртуальные таблицы на практике почти неотличимы от реальных.
Читайте также: