Вторник, 30.04.2024, 12:21
Распределенная обработка данных
Здравствуйте Гость | RSS
Главная страница Интерфейс (продолжение) Регистрация Вход
Меню сайта

Считалка

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Форма входа

§ 7.5  Дополнительные сведения из теории интерфейсов COM (неизменность интерфейсов, полиморфизм, наследование).

Интерфейсы COM не изменяются, причем никогда. При модификации компонента следует не изменять существующий интерфейс, а создать и добавить новый.

Полиморфизм – это способность обрабатывать разные объекты единообразно. Поддержка множественных интерфейсов обеспечивает дополнительные возможности для полиморфизма.

Если два разных компонента поддерживают один и тот же интерфейс, для работы с ними клиент может использовать один и тот же код. Таким образом, клиент может работать с разными компонентами полиморфно.

Множественные интерфейсы поощряют полиморфизм. Чем больше интерфейсов поддерживает компонент, тем меньше может быть каждый из них. Маленький интерфейс представляет один вариант поведения, а большой – несколько вариантов.

Чем больше вариантов поведения поддерживает данный интерфейс, тем более специфичным он становится. Чем специфичнее интерфейс, тем меньше вероятность его повторного использования. Если же интерфейс не используется повторно, то и работающий с ним клиентский код тоже нельзя использовать повторно. (Пример. Полет вертолета: полет, зависание, вращение, вибрация.)

Возможность повторного применения целых архитектур требует тщательного планирования при разработке интерфейсов. Они должны быть адаптируемыми, готовыми к будущим нововведениям.

Чисто абстрактные базовые классы подходят для реализации интерфейсов. Определяя их, мы определяем структуру некоторого блока памяти. Все реализации чисто абстрактных базовых классов, являются блоками памяти однотипной структуры. На рис. 7.4 показана структура памяти для абстрактного базового класса, определяемого следующим кодом:

interface IX{

virtual void _stdcall Fx1()=0;

virtual void _stdcall Fx2()=0;

virtual void _stdcall Fx3()=0;

virtual void _stdcall Fx4()=0;

};

 


Таблица виртуальных функций содержит указатели на функции-члены

Рис.7.4 Пример структуры блока памяти, определяемой абстрактным базовым классом.

 

Память для структуры не выделяется до тех пор, пока абстрактный класс не будет реализован в производном классе. Когда производный класс наследует абстрактному базовому классу, он наследует и эту структуру.

Таблица виртуальных функций, или vtbl – это массив указателей на реализации виртуальных функций. На рисунке первый элемент содержит адрес функции Fx1, реализованной в производном классе. Второй элемент содержит адрес Fx2, и т.д. Слева на рисунке показан указатель на vtbl, (или просто указатель vtbl).

Формат блока памяти для интерфейса COM совпадает с форматом блока памяти, который компилятор С++ генерирует для абстрактного базового класса.

Есть дополнительное требование: все интерфейсы COM должны наследовать интерфейсу IUnknown. Это означает, что первые три элемента vtbl одни и те же для всех интерфейсов COM. Они содержат адреса реализаций трех функций-членов IUnknown.

 

§ 7.6  Указатели vtbl и данные экземпляра.

 Указатель vtbl повышает уровень абстракции в процессе получения указателя на функцию по указателю на базовый класс (дает дополнительную свободу в реализации интерфейса).

Компилятор С++ может генерировать код, в котором класс, реализующий абстрактный базовый класс, хранит вместе с указателем vtbl информацию, специфичную для экземпляра. Например, класс СА в представленном ниже коде реализует абстрактный базовый класс IX, который мы определили раньше:

 

class CA: public IX

{

  public:

 

// Реализация интерфейса  IX.

 

virtual void _stdcall Fx1() {cout << "CA::Fx1” << endl;}

virtual void _stdcall Fx2() {cout << "m_Fx2” << endl;}

virtual void _stdcall Fx3() {cout << "m_Fx3” << endl;}

virtual void _stdcall Fx4() {cout << "m_Fx4” << endl;}

 

// Конструктор

 

CA (double d)                         //инициализация

: m_Fx2(d*d), m_Fx3(d*d*d), m_Fx4(d*d*d*d), m_Fx2(d*d)

{ }

 

// Данные экземпляра

 

double m_Fx2;

double m_Fx3;

double m_Fx4;

};  . . .

Таблица vtbl и данные класса СА, сгенерированные компилятором, показаны на рис. 7.5. Данные экземпляра потенциально доступны через указатель класса СА. Однако обычно клиент не знает, какие именно данные там хранятся, и поэтому не может обращаться к ним.

 

Рис. 7.5 Данные, специфичные для экземпляра, хранятся вместе с указателем vtbl.

В то время как классы С++ могут обращаться к данным экземпляра напрямую, компоненты COM не могут. В COM мы можем работать с компонентом только через функции и никогда через переменные. Это соответствует тому способу, которым мы определяем интерфейсы COM. У чисто абстрактных базовых классов есть только чисто виртуальные функции, они не имеют данных экземпляра.

 

§ 7.7  Множественные экземпляры.

Указатель vtbl позволяет разным экземплярам (объектам) одного класса использовать одну и ту же vtbl.

Если мы создадим два экземпляра СА, то получим два отдельных набора данных экземпляра. Однако эти экземпляры могут совместно использовать одну и ту же vtbl, элементы которой указывают на одни и те же реализации виртуальных функций-членов. (Однако у объектов будут разные данные экземпляра: (рис. 7.6)).

Код:

 

int main()

{

//Создадим первый экземпляр СА

CA * pA1 = new CA (1.5);

 

//Создадим второй экземпляр СА

 

CA * pA2 = new CA (2.75);

. . .

};


Рис. 7.6 Несколько экземпляров класса используют одну vtbl.

 

§ 7.8  Разные классы, одинаковые vtbl.

Сила интерфейсов проявляется в том, что классы, производные от одного интерфейса, клиент может рассматривать одинаково.

Предположим, что мы реализовали класс СВ, который также является производным от IX:

 

class CB: public IX

{

  public:

 

// Реализация интерфейса  IX.

 

virtual void _stdcall Fx1() {cout << "CB::Fx1” << endl;}

virtual void _stdcall Fx2() {cout << "CB::Fx2” << endl;}

virtual void _stdcall Fx3() {cout << "CB::Fx3” << endl;}

virtual void _stdcall Fx4() {cout << "CB::Fx4” << endl;}

};

С помощью указателя на IX клиент может работать как с СА, так и с СВ: (полиморфизм: СА и СВ являются интерфейсом IX)

 

void foo (IX * pIX)

{

pIX -> Fx1();

pIX -> Fx2();

};

int main()

{

// Создать экземпляр СА

CA * pA = new CA(1.789);

// Создать экземпляр СB

CB * pB = new CB;

// Получить указатель IX для СА

IX * pIX = pA;

foo(pIX);

// Получить указатель IX для СB

IX * pIX = pB;

foo(pIX);

.

.

}

Покажем формат структур памяти для данного примера.



Рис. 7.7 Полиморфное использование двух разных классов при помощи абстрактного базового класса.

Из рисунка 7.6 видно, что два класса СА и СВ имеют отдельные и различные данные экземпляра (они не нарисованы, т.к. COM-программистам не важно, что они собой представляют), vtbl и реализацию. Однако доступ к их vtbl может осуществляться одинаково, поскольку формат обеих таблиц один и тот же.
Поиск

Друзья сайта

2024