Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
0495976_C19D7_shpory_s.doc
Скачиваний:
1
Добавлен:
01.03.2025
Размер:
1.82 Mб
Скачать
  1. Абстрактные классы.

Многие классы сходны с классом employee тем, что в них можно дать разумное определение

виртуальным функциям. Однако, есть и другие классы. Некоторые, например, класс shape,

представляют абстрактное понятие (фигура), для которого нельзя создать объекты. Класс shape

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

что невозможно дать осмысленное определение виртуальных функций класса shape:

class shape {

// ...

public:

virtual void rotate(int) { error("shape::rotate"); }

virtual void draw() { error("shape::draw"): }

// нельзя ни вращать, ни рисовать абстрактную фигуру

// ...

};

Создание объекта типа shape (абстрактной фигуры) законная, хотя совершенно бессмысленная

операция:

shape s; // бессмыслица: ``фигура вообще''

Она бессмысленна потому, что любая операция с объектом s приведет к ошибке.

Лучше виртуальные функции класса shape описать как чисто виртуальные. Сделать виртуальную

функцию чисто виртуальной можно, добавив инициализатор = 0:

class shape {

// ...

public:

virtual void rotate(int) = 0; // чисто виртуальная функция

virtual void draw() = 0; // чисто виртуальная функция

};

Класс, в котором есть виртуальные функции, называется абстрактным. Объекты такого класса создать

нельзя:

shape s; // ошибка: переменная абстрактного класса shape

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

class circle : public shape {

int radius;

public:

void rotate(int) { } // нормально:

// переопределение shape::rotate

void draw(); // нормально:

// переопределение shape::draw

circle(point p, int r);

};

Абстрактные классы нужны для задания интерфейса без уточнения каких-либо конкретных деталей

реализации. Например, в операционной системе детали реализации драйвера устройства можно

скрыть таким абстрактным классом:

class character_device {

public:

virtual int open() = 0;

virtual int close(const char*) = 0;

virtual int read(const char*, int) =0;

virtual int write(const char*, int) = 0;

virtual int ioctl(int ...) = 0;

// ...

};

Настоящие драйверы будут определяться как производные от класса character_device.

  1. Аргументы функций по умолчанию.

Класс c o m p l e x включает три конструктора, два из  которых просто подставляют нулевое значение (по умолчанию ),  предоставлены программисту для удобства нотации. Использование  перегрузки типично для конструкторов, но также часто  обнаруживается и для других функций. Такая перегрузка, однако,  весьма трудоемкий обходной путь подстановки аргументов по  умолчанию и, в особенности для более сложных конструкторов,  крайне избыточнa. Следовательно должна быть предоставлена  возможность для непосредственного задания аргументов по  умолчанию. Например: 

        class complex {                      . . .          public:                complex(double r=0, double i=0) { re = r; im = i;}          }; 

    Если завершающий аргумент отсутствует, может быть использовано константное выражение по умолчанию. Например : 

        complex a(1,2);          complex b(1); /* b = complex(1, 0); */          complex c; /* c = complex(0, 0); */ 

  Если составляющая функция такая, как вышеприведенная функция   c o m p l e x не только описана, но и определена, (то есть приведено ее тело) в описании класса, то при обращении к ней может быть выполнена константная подстановка, избегая тем самым обычных накладных расходов по вызову функции. Константная  подстановка функции не является макроподстановкой, семантика такой функции идентична семантике других функций. Любая функция может быть объявлена включаемой (*1) предшествующим указанием  ключевого слова i n l i n e . Включаемые функции могут сделать описания классов крайне раздутым и они в случае разумного использованияа повышают эффективность исполнения, но всегда увеличивают время и память, необходимые для компиляции.  Включаемые функции, таким образом, должны использоваться только в  случае, если ожидается значительное повышение эффективности исполнения. Они были включены в С++ вследствие опыта использования макросов в С. В некоторых приложениях макросы бывают необходимы (и нет возможности определить макрос в составе класса) но значительно чаще они создают хаос тем, что выглядят как функции, но не подчиняются ни синтаксису функций, ни правилам видимости, ни правилам передачи аргументов.

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