Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Объектно-ориентированное программирование и C++....doc
Скачиваний:
22
Добавлен:
08.07.2019
Размер:
188.42 Кб
Скачать

3.4 Разработка классов

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

Объявление класса должно предшествовать его использованию. Как правило, прикладной программист пользуется готовыми базовыми классами, причем ему вовсе не обязательно разбираться во всех спецификациях и во внутренней реализации. Однако, чтобы использовать базовый класс C++, надо обязательно знать какие члены данных и методы вам доступны (а если применяется компонента C++Builder - еще и предоставляемые свойства и события).

3.4.1 Объявление базового класса

C++Builder дает вам возможность объявить базовый класс, который инкапсулирует имена своих свойств, данных, методов и событий. Помимо способности выполнять свою непосредственную задачу объектные методы получают определенные привилегии доступа к значениям свойств и данных класса.

Каждое объявление внутри класса определяет привилегию доступа к именам класса в зависимости от того, в какой секции имя появляется. Каждая секция начинается с одного из ключевых слов: private, protected и public. Листинг 3.1 иллюстрирует обобщенный синтаксис объявления базового класса.

class className

private:

<приватные члены данных> <приватные конструкторы> <приватные методы>

protected:

<защищенные члены данных> <защищенные конструкторы> <защищенные методы>

public:

<общедоступные свойства> <общедоступные члены данных> “збщедоступные конструкторы> <общедоступный деструктор> общедоступные методы>

Листинг 3.1. Объявление базового класса.

Таким образом, объявление базового класса на C++ предоставляет следующие права доступа и соответствующие области видимости:

• Приватные private имена имеют наиболее ограниченный доступ, разрешенный только методам данного класса. Доступ производных классов к приватным методам базовых классов запрещен.

• Защищенные protected имена имеют доступ, разрешенный методам данного и производных от него классов.

• Общедоступные public имена имеют неограниченный доступ, разрешенный методам всех классов и их объектов.

Следующие правила применяются при образовании различных секций объявления класса:

1. Секции могут появляться в любом порядке, а их названия могут встречаться повторно.

2. Если секция не названа, компилятор считает последующие объявления имен класса приватными. Здесь проявляется отличие объявлений класса и структуры - последняя рассматривается по умолчанию как общедоступная.

3. По мере возможности не помещайте члены данных в общедоступную секцию, если только вы действительно не хотите разрешить доступ к ним отовсюду. Обычно их объявляют защищенными, чтобы разрешить доступ только методам производных классов.

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

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

6. Методы (так же как конструкторы и деструкторы), которые содержат более одной инструкции C++, рекомендуется объявлять вне класса.

Листинг 3.2 представляет попытку наполнить объявление базового класса некоторым конкретным содержанием. Отметим характерное для компонентных классов C++Builder объявление свойства Count в защищенной секции, а метода SetCount, реализующего запись в член данных FCount - в приватной секции.

class TPoint { private:

int FCount; // Приватный член данных void _fastcall SetCount(int Value);

protected:

_property int Count = // Защищенное свойство

{ read= FCount, write=SetCount };

double x; // Защищенный член данных

double у; // Защищенный член данных public:

TPoint(double xVal, double yVal); // Конструктор |

double getX(); |

double getY() ;

Листинг 3.2. Объявление базовой компоненты TPoint.

Объявления и определения методов хранятся в разных файлах (с расширениями .h и .срр, соответственно). Листинг 3.3 показывает, что когда методы определяются вне класса, их имена следует квалифицировать. Синтаксис такой квалификации метода, определяющей его область видимости, имеет следующий вид:

<имя класса>::<имя метода>

TPoint::TPoint(double xVal, double yVal)

( // Тело конструктора

void _fastcall TPoint::SetCount( int Value )

{

l

if ( Value i= FCount ) // Новое значение члена данных? {

FCount = Value; // Запись нового значения Update(); // Вызов метода Update } } double TPoint::getX()

// Тело метода getX, квалифицированного в классе^TPoint

}

Листинг 3.3. Определения конструктора и методов вне класса.

После того, как вы объявили класс, его имя можно использовать как идентификатор типа при объявлении объекта этого класса (например,

TPoint* MyPoint;).

3.4.2 Конструкторы и деструкторы

Как следует из названий, конструктор - это метод, который строит в памяти объект данного класса, а деструктор - это метод, который его удаляет. Конструкторы и деструкторы отличаются от других объектных методов следующими особенностями:

• Имеют имя, идентичное имени своего класса.

• Не имеют возвращаемого значения.

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

• Автоматически генерируются компилятором как public, если не были вами объявлены иначе.

• Автоматически вызываются компилятором, чтобы гарантировать надлежащее создание и уничтожение объектов классов.

• Могут содержать неявные обращения к операторам new и delete, если объект требует выделения и уничтожения динамической памяти.

Листинг 3.4 демонстрирует обобщенный синтаксис объявлений конструкторов и деструктора.

class className

{ public:

// Другие члены данных className(); // Конструктор по умолчанию | className(<список параметров;-);// Конструктор с аргументами | className(const className&); // Конструктор копирования

// Другие конструкторы "className(); // Деструктор

// Другие методы };

Листинг 3.4. Объявления конструкторов и деструктора.

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

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

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

• Конструктор копирования предназначен для создания объектов данного класса путем копирования данных из другого, уже существующего объекта этого класса. Такие конструкторы особенно целесообразны для создания копий объектов, которые моделируют динамические структуры данных. Однако, по умолчанию компилятор создает так называемые конструкторы поверхностного копирования (shallow copy constructors), которые копируют только члены данных. Поэтому если какие-то члены данных содержат указатели, сами данные не будут копироваться. Для реализации "глубокого" копирования в код конструктора надо включить соответствующие инструкции.

Класс может объявить только один общедоступный деструктор, имени которого, идентичному имени своего класса, должен предшествовать знак ~ (тильда). Деструктор не имеет параметров и может быть объявлен виртуальным. Если класс не содержит объявления деструктора, компилятор автоматически создаст его.

Обычно деструкторы выполняют операции, обратные тем, что выполняли соответствующие конструкторы. Если вы создали объект класса файл, то в деструкторе этот файл, вероятно, будет закрываться. Если конструктор класса выделяет динамическую память для массива данных (с помощью оператора new), то деструктор, вероятно, освободит выделенную память (с помощью оператора delete) и т.п.