Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Содержание сайт... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Создание отчето... 62816
Модуль Forms 62814
ТЕХНОЛОГИИ ДОСТ... 59352
Пример работы с... 58073
Имитационное мо... 54741
Реклама
Сейчас на сайте
Гостей: 11
На сайте нет зарегистрированных пользователей

Пользователей: 13,073
новичок: DENIS1996
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

Игра Sokoban на Delphi + Блок схемы
Принадлежит ли точка пересечению двух окружностей на Turbo Pascal + Отче...
База данных студентов на Turbo Pascal (Списки) + Пояснительная записка

Реклама



Подписывайся на YouTube канал о программировании, что бы не пропустить новые видео!

ПОДПИСЫВАЙСЯ на канал о программировании
Абстрактные базы как двоичные интерфейсы



Оказывается, применение техники разделения интерфейса и реализации может решить и проблемы совместимости транслятора/компоновщика C++. При этом, однако, определение класса интерфейса должно принять несколько иную форму. Как отмечалось ранее, проблемы совместимости возникают из-за того, что разные трансляторы имеют различные соображения по поводу того, как
1. передавать особенности языка на этапе выполнения;
2. символические имена будут представлены на этапе компоновки.
Если бы кто-нибудь придумал, как скрыть детали реализации транслятора/компоновщика за каким-либо двоичным интерфейсом, это сделало бы написанные на C++ библиотеки DLL значительно более широко используемыми.
Двоичная защита, то есть тот факт, что класс интерфейса C++ не использует языковых конструкций, зависящих от транслятора, решает проблему зависимости от транслятора/компоновщика. Чтобы сделать эту независимость более полной, необходимо в первую очередь определить те аспекты языка, которые имеют одинаковую реализацию в разных трансляторах. Конечно, представление на этапе выполнения таких сложных типов, как С-структуры (structs), может быть выдержано инвариантным по отношению к трансляторам. Это – основное, что должен делать системный интерфейс, основанный на С, и иногда это достигается применением условно транслируемых определений типа прагм (pragmas) или других директив транслятора. Второе, что следует сделать, – это заставить все компиляторы проходить параметры функций в одном и том же порядке (слева направо, справа налево) и зачищать стек также одинаково. Подобно совместимости структур, это также решаемая задача, и для унификации работы со стеком часто используются условные директивы транслятора. В качестве примера можно привести макросы WINAPI/WINBASEAPI из Win32 API. Каждая извлеченная из системных DLL функция определена с помощью этих макросов:
WINBASEAPI void WINAPI Sleep(DWORD dwMsecs);



Каждый разработчик транслятора определяет эти символы препроцессора для создания гибких стековых фреймов. Хотя в среде производителей может возникнуть желание использовать аналогичную методику для определений всех методов, фрагменты программ в этой главе для большей наглядности ее не используют.
Третье требование к независимости трансляторов – наиболее уязвимое для критики из всех, так как оно делает возможным определение двоичного интерфейса: все трансляторы C++ с заданной платформой одинаково осуществляют механизм вызова виртуальных функций. Действительно, это требование единообразия применимо только к классам, не имеющим элементов данных, а имеющим не более одного базового класса, который также не имеет элементов данных. Вот что означает это требование для следующего простого определения класса:
class calculator
{
public: virtual void add1(short x);
virtual void add2(short x, short y);
};



Все трансляторы с данной платформой должны создать эквивалентные последовательности машинного кода для следующего фрагмента программы пользователя:
extern calculator *pcalc;
pcalc->add1(1);
pcalc->add2(1, 2);



Отметим, что требуется не идентичность машинного кода на всех трансляторах, а его эквивалентность. Это означает, что каждый транслятор должен делать одинаковые допущения относительно того, как объект такого класса размещен в памяти и как его виртуальные функции динамически вызываются на этапе выполнения.
Впрочем, это не такое уж блестящее решение проблемы, как может показаться. Реализация виртуальных функций на C++ на этапе выполнения выливается в создание конструкций vptr и vtbl практически на всех трансляторах. При этой методике транслятор молча генерирует статический массив указателей функций для каждого класса, содержащего виртуальные функции. Этот массив называется vtbl (virtual function table – таблица виртуальных функций) и содержит один указатель функции для каждой виртуальной функции, определенной в данном классе или в ее базовом классе. Каждый объект класса содержит единственный невидимый элемент данных, именуемый vptr (virtual function pointer – указатель виртуальных функций); он автоматически инициализируется конструктором для указания на таблицу vtbl класса. Когда клиент вызывает виртуальную функцию, транслятор генерирует код, чтобы разыменовать указатель vptr , занести его в vtbl и вызвать функцию через ее указатель, найденный в назначенном месте. Так на C++ обеспечивается полиморфизм и диспетчеризация динамических вызовов. Рисунок 1.5 показывает представление на этапе выполнения массивов vptr/vtbl для класса calculator , рассмотренного выше.
Фактически каждый действующий в настоящее время качественный транслятор C++ использует базовые концепции vprt и vtbl . Существует два основных способа размещения таблицы vtbl : с помощью CFRONT и корректирующего переходника ( adjuster thunk ). Каждый из этих приемов имеет свой способ обращения с тонкостями множественного наследования. К счастью, на каждой из имеющихся платформ доминирует один из способов (трансляторы Win32 используют adjuster thunk , Solaris – стиль CFRONT для vtbl ). К тому же формат таблицы vtbl не влияет на исходный код C++, который пишет программист, а скорее является артефактом сгенерированного кода. Желающие узнать подробности об этих двух способах могут обратиться к прекрасной книге Стэна Липпмана «Объектная модель C++ изнутри» (Stan Lippman. Inside C++ Object Model).
Основываясь на столь далеко идущих допущениях, теперь можно решить проблему зависимости от транслятора. Предполагая, что все трансляторы на данной платформе одинаково реализуют механизм вызова виртуальной функции, можно определить класс интерфейса C++ так, чтобы глобальные операции над типами данных определялись в нем как виртуальные функции; тогда можно быть уверенным, что все трансляторы будут генерировать эквивалентный машинный код для вызова методов со стороны клиента. Это предположение об единообразии означает, что ни один класс интерфейса не имеет элементов данных и ни один класс интерфейса не может быть прямым потомком более чем одного класса интерфейса. Поскольку в классе интерфейса нет элементов данных, эти методы практически невозможно использовать.
Чтобы подчеркнуть это обстоятельство, полезно определить члены интерфейса как простые виртуальные функции, указав, что класс интерфейса задает только возможность вызова методов, а не их реализацию.
// ifaststring.h
class IFastString
{
public: virtual int Length(void) const = 0;
virtual int Find(const char *psz) const = 0;
};



Определение этих методов как чисто виртуальных также дает знать транслятору, что от класса интерфейса не требуется никакой реализации этих методов. Когда транслятор генерирует таблицу vtbl для класса интерфейса, входная точка для каждой простой виртуальной функции является или нулевой (null), или точкой входа в С-процедуру этапа выполнения (_purecall в Microsoft C++), которая при вызове генерирует логическое утверждение. Если бы метод не был определен как чисто виртуальный, транслятор попытался бы включить в соответствующую входную точку vtbl системную реализацию метода класса интерфейса, которая в действительности не существует. Это вызвало бы ошибку компоновки. Определенный таким образом класс интерфейса является абстрактным базовым классом. Соответствующий класс реализации должен порождаться классом интерфейса и перекрывать все чисто виртуальные фyнкции содержательными реализациями. Эта наследственная связь проявится в объектах, которые в качестве своего представления имеют двоичное надмножество представления класса интерфейса (которое как раз и есть vptr/vtbl). Дело в том, что отношение «является» («is-a») между порождаемым и базовым классами применяется на двоичном уровне в C++ так же, как и на уровне моделирования в объектно-ориентированной разработке:
Опубликовал Kest July 11 2009 00:32:52 · 0 Комментариев · 8673 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Страница 1 из 2 1 2 >
Комментарии
Нет комментариев.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
Cтатьи Королевств...
Добавление к ссы...
PHP: настольная к...
Crypt32
DAlarm
Приемы программир...
OnlineIP
Песочные часы
ИНТЕРНЕТ ПРОГРАММ...
Counter [Исходник...
C++ для начинающих
Delphi. Учимся на...
C++ Builder: Книг...
PHP, MySQL и Drea...
Пользовательская...
Трассировка прово...
Delphi Russian Kn...
DateEdit
SUIPack
Таймер и секундомер

Топ загрузок
Приложение Клие... 100422
Delphi 7 Enterp... 84960
Converter AMR<-... 20062
GPSS World Stud... 11975
Borland C++Buil... 11408
Borland Delphi ... 8380
Turbo Pascal fo... 7008
Visual Studio 2... 4985
Калькулятор [Ис... 4631
FreeSMS v1.3.1 3530
Случайные статьи
Palladium
Передача сообщений...
Протокол динамичес...
Оценка недвижимост...
Процесс самофокуси...
Предикат поиска ст...
Разработчик прилож...
Данные инфографики...
Процедура SetActiv...
Потери на стыках в...
Vemeo.
Различные команды ...
Проектирование в п...
Водород можно полу...
Поле приоритета вк...
Архитектура Ethern...
Вызов функций, нап...
Сортировка списков
4. Как гарантирова...
Функция GraphResul...
Процедуры и функци...
Механизм наследова...
Мосты, которые при...
Основные понятия
Форма кучи
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?