Массивы. До сих пор мы говорили о встроенных типах, т.е

Классы и объекты

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

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

class Complex {

public:

int real; // вещественная часть

int imaginary; // мнимая часть

void Add(Complex x);

// прибавить комплексное число

};

Приведенный выше пример - упрощенное определение класса Complex, представляющее комплексное число. Комплексное число состоит из вещественной части - целого числа real и мнимой части, которая представлена целым числом imaginary. real и imaginary - это атрибуты класса. Для класса Complex определена одна операция или метод - Add.

Определив класс, мы можем создать переменную типа Complex:

Complex number;

Переменная с именем number содержит значение типа Complex, то есть содержит объект класса Complex. Имея объект, мы можем установить значения атрибутов объекта:

number.real = 1;

number.imaginary = 2;

Операция "." обозначает обращение к атрибуту объекта. Создав еще один объект класса Complex, мы можем прибавить его к первому:

Complex num2;

number.Add(num2);

Как можно заметить, метод Add выполняется с объектом. Имя объекта (или переменной, содержащей объект, что, в сущности, одно и то же), в данном случае, number, записано первым. Через точку записано имя метода - Add с аргументом - значением другого объекта класса Complex, который прибавляется к number. Методы часто называются сообщениями. Но чтобы послать сообщение, необходим получатель. Таким образом, объекту number посылается сообщение Add с аргументом num2. Объект number принимает это сообщение и складывает свое значение со значением аргумента сообщения.

Определение методов класса

Данные рассуждения будут яснее, если мы определим, как выполняется операция сложения.

void Complex::Add(Complex x)

{

real = real + x.real;

imaginary = imaginary + x.imaginary;

}

Первые две строки говорят о том, что это метод Add класса Complex. В фигурных скобках записано определение операции или метода Add. Это определение означает следующее: для того чтобы прибавить значение объекта класса Complex к данному объекту, надо сложить вещественные части и запомнить результат в атрибуте вещественной части текущего объекта. Точно так же следует сложить мнимые части двух комплексных чисел и запомнить результат в атрибуте текущего объекта, обозначающем мнимую часть.

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

Теперь приведем этот небольшой пример полностью:

// определение класса комплексных чисел

class Complex {

public:

int real; // вещественная часть

int imaginary; // мнимая часть

void Add(Complex x);

// прибавить комплексное число

};

// определение метода сложения

void

Complex::Add(Complex x)

{

real = real + x.real;

imaginary = imaginary + x.imaginary;

}

int

main()

{

Complex number;

number.real = 1;

number.imaginary = 3;

Complex num2;

num2.real = 2;

num2.imaginary = 1;

number.Add(num2);

// прибавить значение второго объекта к первому

return 1;

}

В языке Си++ можно сделать так, что класс будет практически неотличим от предопределенных встроенных типов при использовании в выражениях. Для класса можно определить операции сложения, умножения и т.д. пользуясь стандартной записью таких операций, т.е. x + y. В языке Си++ считается, что подобная запись - это также вызов метода с именем operator+ того класса, к которому принадлежит переменная x. Перепишем определение класса Complex:

// определение класса комплексных чисел

class Complex

{

public:

int real; // вещественная часть

int imaginary; // мнимая часть

// прибавить комплексное число

Complex operator+(const Complex x) const;

};

Вместо метода Add появился метод operator+. Изменилось и его определение. Во-первых, этот метод возвращает значение типа Complex (операция сложения в результате дает новое значение того же типа, что и типы операндов). Во-вторых, перед аргументом метода появилось ключевое слово const. Это слово обозначает, что при выполнении данного метода аргумент изменяться не будет. Также const появилось после объявления метода. Второе ключевое слово const означает, что объект, выполняющий метод, над будет изменен. При выполнении операции сложения x + y над двумя величинами x и y сами эти величины не изменяет. Теперь запишем определение операции сложения:

Complex

Complex::operator+(const Complex x) const

{

Complex result;

result.real = real + x.real;

result.imaginary = imaginary + x.imaginary;

return result;

}

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

// определение класса комплексных чисел

class Complex

{

public:

int real; // вещественная часть

int imaginary; // мнимая часть

// прибавить комплексное число

Complex operator+(const Complex x) const;

// прибавить целое число

Complex operator+(long x) const;

};

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

Complex c1;

Complex c2;

long x;

c1 + c2;

c2 + x;

Аналогично можно задавать значения аргументов методов по умолчанию.

Как уже отмечалось раньше, выбор имен - это не праздный вопрос. Существует множество систем именования классов.

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

Complex, String, StudentLibrarian

Имена методов классов также начинаются с большой буквы:

Add, Concat

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

real, classElement

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

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

int days[12];

days[0] = 31; // январь

days[1] = 28; // февраль

days[2] = 31; // март

days[3] = 30; // апрель

days[4] = 31; // май

days[5] = 30; // июнь

days[6] = 31; // июль

days[7] = 31; // август

days[8] = 30; // сентябрь

days[9] = 31; // октябрь

days[10] = 30; // ноябрь

days[11] = 31; // декабрь

В первой строчке мы объявили массив из 12 элементов типа int и дали ему имя days. Остальные строки примера – присваивания значений элементам массива. Для того, чтобы обратиться к определенному элементу массива, используют операцию индексации []. Как видно из примера, первый элемент массива имеет индекс 0, соответственно, последний – 11.

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

Предположим, мы хотим распечатать все элементы массива days. Для этого удобно воспользоваться циклом for.

for (int i = 0; i < 12; i++) {

cout << days[i];

}

Следует отметить, что при выполнении программы границы массива не контролируются. Если мы ошиблись и вместо 12 в приведенном выше цикле написали 13, то компилятор не выдаст ошибку. При выполнении программа попытается напечатать 13-е число. Что при этом случится, вообще говоря, не определено. Быть может, произойдет сбой программы. Более вероятно, что будет напечатано какое-то случайное 13-е число. Выход индексов за границы массива – довольно распространенная ошибка, которую иногда очень трудно обнаружить. В дальнейшем при изучении классов мы рассмотрим, как можно переопределить операцию [] и добавить контроль за индексами.

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

Рассмотрим еще один пример. Предположим, что имеется массив из 100 целых чисел, и его необходимо отсортировать, т.е. расположить в порядке возрастания. Сортировка методом "пузырька" – наиболее простая и распространенная – будет выглядеть следующим образом:

int array[100];...for (int i = 0; i < 99; i++) { for (int j = i + 1; j < 100; j++) { if (array[j] < array[i]) { int tmp = array[j]; array[j] = array[i]; array[i] = tmp; } }}

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

int m[10][5];

представляет матрицу целых чисел размером 10 на 5. Общее количество целых чисел в массиве m равно 50.

Обращение к элементам многомерных массивов аналогично обращению к элементам векторов: m[1][2] обращается к третьему элементу второй строки матрицы m.

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

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

int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

При инициализации многомерных массивов каждая размерность должна быть заключена в фигурные скобки:

double temp[2][3] = { { 3.2, 3.3, 3.4 }, { 4.1, 3.9, 3.9 } };

Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: