Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
SHPORS~1.doc
Скачиваний:
2
Добавлен:
01.04.2025
Размер:
201.73 Кб
Скачать

14. Конкретные и абстрактные типы. Виртуальные функции.

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

Класс, представляющий конкретный тип, предназначен для того, чтобы:

1. Точно соответствовать данному частному понятию и стратегии реализации.

2. Обеспечивать быстродействие и затраты памяти, сравнимые с «написанным вручную» кодом за счет применения встраивания и операций, полностью использующих особенности самого понятия и его реализации.

3. В минимальной степени зависеть от других классов.

4. Быть понятным и пригодным к использованию независимо от других классов.

Результат – тесная связь между пользовательским кодом и кодом реализации.

Пример: реализация стека. Требования: четкий интерфейс, запретить доступ к реальному стеку, инициализация.

// Интерфейс stack.h class stack {char *s; int top, size; public: char pop(); void push (char); stack (); //конструктор по умолчанию stack(int size);}; char stack::pop() {return s[top--];//стек увеличивается в обратном порядке};

Пример конкретного использования стека: void f(stack& stk) {stk.push(‘c’); if (stk.pop()!=’c’) Error(); }; // после изменения стека программу надо перекомпилировать.

Пример более абстрактного использования стека: class stack {public: virtual push(char)=0; virtual char pop()=0;//функции push и pop абстрактные, класс stack абстрактный }. Абстрактный класс позволяет не перекомпилировать исходный текст программ, который используют этот тип при изменении реализации типа.

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

1. Определить понятие таким образом, чтобы позволить сосуществовать в программе нескольким его реализациям;

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

3. Минимизировать зависимость каждой реализации от других классов.

Абстрактная реализация стека: class stack {public: virtual void push(char)=0; virtual char pop()=0;};

1. Это позволит не перекомпилировать исходный текст при изменении реализации типа.

2. Абстрактный тип требует, чтобы ниже в программе он был доопределен в каком-нибудь производном классе.

3. Для абстрактного класса нельзя описывать экземпляры: stack stk;//Err

void f(stack *stk) {stk->push(‘c’); if (stk->pop()!=’c’ Error…;} void main(){ Array_Stack(произв от stack класс) as [100]; f(as);…} class Array_Stack: public Stack {char *v; int top, stsize; public: … char pop(); void push(char);}; char Array_Stack::pop(){return v[top--];};

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

Вызов f(): void main(){ array_Stack as(100); f(as) …}; class array_Stack:public Stack {char *v; int size; public: … char pop(); void push(char);}; char array_Stack::pop() {return v[top--];}

Абстрактные классы полезны при создании больших комплексов программ, они позволяют проследить независимость интерфейса от реализации.

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

Class A {public: virtual void f(){cout<<”I’m A”;};} class B:public A {public: void f(){cout<<”I’m B”;};} void g() {A a; B b; a.f(); b.f(); g1(&a); g1(&b);} void g1(A *pa){pa->f();}

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

При использовании виртуальных функций необходимо оценить сложность и объем памяти. 1. Эффективность использования с точки зрения сложности (вычислительной). 2. Эффективность использования с точки зрения памяти.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]