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

3 Объединения

Объединение (union) - это структура (struct), у которой все элементы расположены по одному и тому же адресу. В конкретный момент может храниться значение только одного из элементов.

union FloatValue

{

float d;

long bytes;

};

// Анализ внутреннего представления float:

FloatValue dv;

dv.d = 100;

cout << dv.bytes << endl;

Анонимное объединение не имеет имени и не определяет типа.

union { int a; char* p; };

a = 1;

p = "name"; // a и p бессмысленно использовать одновременно

Класс с конструктором, деструктором и операцией копирования не может быть членом объединения. Объединение может содержать функции-элементы.

4 Классы

Классы используются в С++ для определения пользовательских типов данных. Класс аналогичен структуре. В описание классов входят элементы данных (data members) и функции-элементы (member functions).

Важным признаком класса являются уровни доступа; элементы класса можно объявлять как закрытые (private) - доступные только из функций-элементов данного класса, защищенные (protected) - доступные только из функций-элементов данного класса и классов, производных от него, и открытые (public) - доступные отовсюду (через имя объекта класса). Доступ к закрытым элементам через открытые функции-элементы называется инкапсуляцией.

Приведем определение класса Country:

class Country

{

private:

string name;

double area;

long population;

public:

string getName();

double getArea();

long getPopulation();

void setName(char* value);

void setArea(double value);

void setPopulation(long value);

double density();

};

Функции-элементы getName(), getArea(), getPopulation(), setName(), setArea() и setPopulation() обеспечивают доступ к закрытым элементам данных класса. Функция-элемент density() используется для вычисления плотности населения.

Функции-элементы могут быть реализованы отдельно. Для указания принадлежности функции классу используют операцию разрешения области видимости (::). Доступ к элементам данных в теле функции-элемента осуществляется непосредственно (без указания имени объекта и использования операции обращения к элементу). При реализации классов в модулях определение классов размещают в заголовочном файле, а определение функций-элементов - в файле реализации. Ниже приводится реализация функции density():

double Country::density()

{

return population / area;

}

Функцию-элемент можно не только объявить, но и определить в теле класса. Такая функция является inline-функцией.

class Country

{

private:

string name;

double area;

long population;

public:

string getName() const { return name; }

double getArea() const { return area; }

long getPopulation() const { return population; }

void setName(string value) { name = value; };

void setArea(double value) { area = value; }

void setPopulation(long value) { population = value; }

double density();

};

Указание после заголовков функций-элементов const обеспечивает невозможность изменения каких-либо элементов данных при выполнении функции.

Имя класса используется для создания объектов. Объект класса не может быть элементом того же класса. Обращение к функциям-элементам аналогично обращению к элементам данных:

Country someCountry;

someCountry.setName("France");

someCountry.setArea(551500);

someCountry.setPopulation(57981000);

cout << someCountry.density();

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

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

Деструктор - специальная функция-элемент, имеющая имя ~Имя_Класса. Она автоматически вызывается каждый раз, когда объект класса выходит из текущей области видимости или операция delete применяется к указателю на класс. Деструктор не имеет параметров и не может быть перегружен.

Инициализация одного объекта класса другим объектом класса может происходить явно, при передаче объекта класса как параметра функции, при возврате объекта класса из функции. При этом используется конструктор копирования вида X::X(const X&), который либо создается автоматически, либо определяется пользователем. Конструктор копирования для класса X имеет вид:

X::X(const X&);

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

Определение массива объектов класса аналогично определению массива любого типа. Для каждого элемента массива вызывается конструктор. При наличии конструкторов без параметров (или отсутствии явных конструкторов) допустима запись:

X x[10]; // Для 10 элементов вызываются конструкторы

Если у конструктора ровно 1 параметр, можно применить запись, аналогичную инициализации массивов встроенных типов:

X x[10] = {1, 2, 3, 4, 5};

Для 5 элементов вызываются конструкторы с параметром int (или double), а для остальных - конструкторы без параметров.

Если конструкторы требуют более одного параметра, их следует вызывать явно:

X x[3] = {X(1, "a"), X(2, "b"), X(3, "c")};

Деструкторы элементов вызываются в обратном порядке.

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

MyClass f(MyClass t) // Вызов конструктора копирования

{

return t;

} // Вызов деструктора

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

MyClass& f(MyClass& t) // Конструктор не вызывается

{

return t;

} // Деструктор не вызывается

Аналогично функция может возвращать ссылку на объект.

Если нежелательно менять в функции данный объект, то он может быть передан как ссылка на константу.

const MyClass& f(const MyClass& t)

{

return t;

}

Функция-элемент которая не может изменять объект, для которого вызвана, называется константной. Между списком параметров и телом функции необходимо задать служебное слово const. Если константная функция-элемент определена вне тела класса, то спецификатор const нужно задавать и в объявлении, и в определении функции.

Константная функция-элемент может быть вызвана для объекта-константы:

const Country c = "France";

cout << c.getName();

c.setName("Belgium"); // Ошибка

Константную функцию-элемент можно перегружать неконстантной функций с тем же прототипом.

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

Функции-элементы, которые предоставляют пользователю доступ к закрытым данным класса, называются функциями доступа. Функции доступа могут обращаться к объекту класса только по чтению (как функции getName(), getArea(), getPopulation() для класса Country), или по записи (как функции setName(), setArea(), setPopulation() для того же класса). Чаще всего функции, предназначенные для чтения элементов, описывают со спецификатором const.

В объекте класса хранятся элементы данных, но не функции-элементы, которые являются общими для всех объектов данного класса. Для того, чтобы в функции-элементе можно было обращаться к элементам объекта, в нее неявно передается как параметр константный указатель this. Этот указатель содержит адрес того объекта класса, для которого была вызвана функция-элемент. Тип этого указателя совпадает с типом его класса. Каждое обращение к элементу класса в функции-элементе транслятор переводит в обращение с помощью this. Например, ранее использовавшаяся функция-элемент

double Country::density()

{

return population / area;

}

переводится в обычную функцию (имя ее дано условно):

double Country_density(Country *const this)

{

return this->population / this->area;

}

Разыменовывая this (использованием *this), мы получаем сам объект. При необходимости к можно обращаться явно, например когда функция-элемент получает в качестве параметра объект или ссылку на объект своего класса и нужно проверить, не получила ли она тот объект, для которого вызвана:

bool Country::isEqual(Country& c) // сравнение двух стран

{

if (this == &c)

. . .

}

Другой пример использования this - возвращение функцией-элементом объекта, для которого она была вызвана:

Country& Country::getCountry()

{

. . .

return *this;

}

Иногда также есть необходимость помещать указатель на свой объект в некоторый массив указателей.

Внутри функции с описателем const тип указателя this будет константным указателем на константу.

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