Перейти к содержанию
Форекс Форум трейдеров Академии «MasterForex-V»

Начальное обучение (Теория)


Рекомендуемые сообщения

Пространство имен

 

Пространство имен (namespace) является фундаментальной концепцией C++. Пространство имен - это группа имен, в которой имена не совпадают. Исключением являются имена перегружаемых функций и переменные с различными областями действия. Имена в различных пространствах имен не конфликтуют. Например, можно использовать имя my_adress в двух различных классах (это же относится к структурам и объединениям). C++ также позволяет определить пространства имен при помощи ключевого слова namespace . Такие пространства имен вводятся для снижения вероятности конфликта имен и полезны в случае использования имен из нескольких различных библиотек.

 

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

 

Синтаксис:

namespace name

{

// объявления и определения имен

}

 

Аргументом спецификатора namespace (то есть name ) является идентификатор пространства имен.

 

Чтобы обратиться к чему-нибудь в пространстве namespace_name, достаточно обратиться непосредственно к члену, используя оператор определения области видимости (::): namespace_name::member .

 

Однако, при многократном использовании члена member такая запись становится слишком громоздкой. Инструкция using заставляет компилятор признавать дальнейшее использование этому члену пространства namespace_name без дополнительного определения имени этого пространства:

using namespace_name::member;

 

Инструкция using namespace заставляет компилятор признавать все члены пространства имен namespace_name:

using namespace namespace_name;

 

В приведенном ниже примере глобальные переменные Cary и Hugh объявляются в пространстве имен grants:

namespace grants

{

int Cary = 0;

int Hugh = 1;

}

Вне пространства имен grants переменные могут быть упомянуты как grants::Cary и grants::Hugh. Но можно сократить эту запись, если добавить такую инструкцию:

using grants::Cary;

 

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

using namespace grants;

Ссылка на комментарий
Поделиться на другие сайты

  • Ответов 34
  • Создана
  • Последний ответ

Топ авторов темы

Топ авторов темы

Изображения в теме

Директивы препроцессора

 

#include <iostream.h>

Это так называемая директива препроцессора. Все директивы препроцессора начинаются с символа #. Конкретно директива include нужна для включения некоторого файла в вашу программу. Тут мы включаем файл iostream.h. Он нужен для того, чтобы мы в нашей программе могли что-ниюудь вводить с клавиатуры или выводить на экран. Этот include пишется почти всегда. После директив препроцессора точка с запятой не ставится.

До компиляция (т. е. превращение в машинные коды) вашей программы происходят некоторые действия - а именно сначала выполняются так называемые директивы препроцессора, а уже потом - непосредственно компиляция. Директивы препроцессора могут, например, включать в файл вашей программы другие файлы (это мы делаем с помощью директивы #include), определять некоторые константы (директива #define) и многое другое.

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

 

Перед любой директивой препрцессора пишется знак #.

 

Давайте немного приоткроем покров над тайной директив препроцессора на маленьком примере. Этот пример будет специфичен для Visual C++, но это не должно нас особенно тревожить - сейчас нам важно просто понять, как это все работает. Итак, создайте на Visual C++ новый проект для консольного приложения Для файла *.cpp задайте имя test.cpp. В качестве текста программы введите

 

#include "test2.h"

#define pi 3.14

void main()

{

float z=2*pi;

}

 

Пока текст нас не слишком должен волновать. Если не все понимаете в тексте - не беда. Принцип здесь такой - #include влючает указанный файл в наш файл. У нас это файл test2.h. Создайте его (например в Блокноте) в той же папке, где находятся все остальные файлы вашего проекта. В нем напечатайте следующий текст (на самом деле можно напечатать все что угодно - это не принципиально):

 

struct v{

int x, y;

};

 

Еще одна директива препроцессора в нашей программе - это #define. Она просто пределяет константу pi, которую мы парой строчек ниже используем.

 

Теперь для просмотра того, что получается после выполнения директив препроцессора, измените настройки нашего проекта. Нажимайте Alt+F7 (или меню Project и далее Settings) и переходим на вкладку C/C++. В ней меняем содержимое окошка Project Options:

 

post-35276-1267508747,1.gif

 

Из этого окошка все удалите, и напечатайте там

/MLd /Fo"Debug/" /P

 

Пока мы это обсуждать не будем, отметим только, что с такими параметрами вы получите в папке проекта файл с результатом работы препроцессора. Закройте окно настроек нажав на OK.

 

Компилируем программу (клавиша F7). В папке с файлами проекта появится файл test.i со следующим текстом:

 

#line 1 "D:\\_programming\\cpp\\test\\test.cpp"

#line 1 "D:\\_programming\\cpp\\test\\test2.h"

struct v{

int x, y;

};

 

#line 2 "D:\\_programming\\cpp\\test\\test.cpp"

 

void main()

{

float z=2*3.14;

}

 

Как вы видите, препроцессор поработал - вставил файл test2.h в наш файл и заменил pi на значение константы:

...

float z=2*3.14;

 

 

Так что работу препроцессера мы немного посмотрели.

Ссылка на комментарий
Поделиться на другие сайты

Встраиваемые (inline) функции

 

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

 

Встраиваемые (inline) функции как раз и решают эту проблему. Оформляется такая функция как и обычная, только с ключевым словом inline. Но при компиляции тело функции подставляется во все места ее вызова. Минусы и плюсы тут меняются местами по сравнению с обычной функцией: вызов такой функции идет быстрее, а место exe-файл занимает больше. Вот пример:

...

//Встраиваемая функция.

inline int f(int a, int b)

{

return a*b;

}

void main()

{

//Вызов функции.

cout<<f(23, 45)<<"\n";

cout<<f(-23, 77)<<"\n";

}

 

Надо сказать, что разные компиляторы по-разному работают с inline-функциями. Если компилятор не может сделать функцию встраиваемой, то он делает ее обычной. Например, такое может случится с рекурсивной функцией.

Ссылка на комментарий
Поделиться на другие сайты

Адрес переменной

 

Операционная система Windows выделяет каждой программе 4 Гб адресного пространства. В реальности, конечно, такой оперативной памяти нет (хотя кто знает, что будет через пару-тройку лет ;)), но каждая программа искренне думает, что у нее есть столько места.

 

Каждый байт адресного пространства имеет свой адрес. Адрес - это просто некоторое число. В Windows адрес выглядит приблизительно так: 0x0D56FF23. Тут префикс 0x означает что это число в шестнадцатеричном виде. Цифры шестнадцатеричного числа - это обычные числа от 0 до 9 и буквы A, B, C, D, E, F. Обратите внимание, что в адресе 8 знаков (так и должно быть, так как у каждой программы 4 Гб адресного пространства).

 

Рассмотрим подробнее, что происходит, когда вы пишете в вашей программе что-то вроде

int z;

 

В этом случае в адресном пространстве вашей программы несколько байт (а именно столько, сколько надо на хранение одного целого - скорей всего это будет 4 байта) получают имя z. И это очень удобно - запись в эти ячейки идет не по их адресу (который выглядит как-то вроде 0x00FD240A) а по удобному имени z. Эти байты выделяются в определенном месте адресного пространства. Адрес первого байта нашего числа z будет начальным адресом все переменной z.

 

Адрес можно получить непосредственно. Для этого служит оператор взятия адреса & (называется амперсанд). Вот пример:

int z;

cout<<&z; //Выводим на экран адрес переменной z.

 

Указаный фрагмент выведет что-то вроде 0x0012FF7C.

 

Вот еще пример:

int z[3]; //Массив

cout<<z; //Адрес начального элемента массива.

 

Тут выведется адрес начала массива (т. е. адрес его нулевого элемента). Таким образом имя массива - это адрес его начала.

Ссылка на комментарий
Поделиться на другие сайты

Указатели

 

Указатель - одно из важных понятий языка C/C++. Начинающие программисты поначалу путаются, но со временем все должно встать на свои места.

 

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

 

Указатели различаются по типам. Например, указатель на целое может хранить адрес переменной целого типа, а указатель на тип float - адрес переменной типа float.

 

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

int * p1; // Указатель на целое.

bool * p2; // Указатель на тип bool.

 

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

 

Вот пример на первый способ:

int z=20;

int *p=&z;

 

Тут мы в указатель p записали адрес переменной z.

 

А вот пример на второй способ инициалиазации указателя - через ключевое слово new:

int *p=new int;

 

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

 

И в первом, и во втором способах в переменной p будет храниться указатель (адрес) целого типа. Для того, чтобы через этот адрес работать с тем местом, на котрое он указывает (т. е. в нашем случае с некоторым целым числом), мы используем так называемое разыменование указателя. Вот пример:

...

*p=123; //Записываем 123 в место, на которое указывает указатель p.

cout<<p<<"\n"; //Выведется некий адрес (например, 0x0012FF7C)

cout<<*p<<"\n"; //Выведется 123;

 

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

 

Таким образом по сути разыменование указателя - это доступ к тому месту на которое указатель указывает.

 

Для указателей существует некий аналог нуля - это значение NULL. Вот пример:

int *p=NULL;

 

На самом деле NULL определена как 0, поэтому в большинстве способов можно писать 0 вместо NULL.

Ссылка на комментарий
Поделиться на другие сайты

Преобразование типов

 

Преобразование типов - это приведение (превращение) одного типа в другой. Такое преобразование созможно далеко не всегда. А иногда в нем вообще нет особой необходимости - например, когда вы присваиваете переменной типа float значение переменной типа int - тут нет никакой потери точности, так что компилятор даже не выдаст вам предупреждения. А вот, например, обратный пример:

...

int a;

float b=2.78;

...

a=b; //Потеря точности!

 

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

 

Для того, чтобы компилятор не ругался, мы сделаем преобразование типа float к типу int. Вот так:

...

a=(int)b;

...

 

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

...

char ch='A';

//Выведется 65 - код символа 'A'.

cout<<(int)ch;

 

int a=7;

//Раздастся звонок (код 7).

cout<<(char)a;

...

 

На самом деле такое преобразование будет возможно, так как char - это тоже целочисленный тип как и int.

Ссылка на комментарий
Поделиться на другие сайты

Оператор sizeof

 

Оператор sizeof позволяет выяснить, сколько байт занимает тот или иной тип. В качестве параметра он принимает или название типа, или переменную соответствующего типа. Вот пример:

int z;

cout<<sizeof(int)<<"\n"; //Выведется 4.

cout<<sizeof(z)<<"\n"; //Выведется 4.

 

Параметр может быть не только встроенным типом. Пример со структурой:

struct vector

{

float x;

float y;

};

void main()

{

vector s;

cout<<sizeof(s)<<"\n"; //Выведется 8.

}

 

Пример выведет 8, так как float занимает 4 байта и в нашей структуре 2 переменной типа float.

Ссылка на комментарий
Поделиться на другие сайты

Работа со строками

 

Вообще говоря в C/C++ нет строкового типа. Его роль выполняет либо указатель на char, либо массив char'ов. Для работы с такими строками в C++ есть несколько функций, тиена которых начинаются на str. Вот пример их использования:

#include <iostream.h>

#include <string.h>

void main()

{

char* ch="Roman";

char ch1[30];

//Показывем длину строки

cout<<strlen(ch)<<"\n";

//Копируем строку

strcpy(ch1, ch);

cout<<ch1<<"\n";

//Длина скопированной строки такая же, как и у старой

cout<<strlen(ch1)<<"\n";

//Сравнение строк

if(strcmp(ch, "Roma")==0)

{

cout<<"Strings are equal\n";

}

else

{

cout<<"Strings are not equal\n";

}

//Конкатенация (сложение) строк

strcpy(ch1, "Roman");

strcat(ch1, " Alexeev");

//Выведется "Roman Alexeev"

cout<<ch1<<"\n";

}

 

Для использования таких функций мы должны написать соответствующий include:

...

#include <string.h>

...

 

Пару слов следует сказать о функции strcmp. Она возвращает ноль, если строки равны; отрицательное число, если строка, задаваемая первым параметром, расположена в алфавитном порядке раньше строки, задаваемой вторым параметром; и положительное число, если первая строка расположена в алфавитном порядке дальше, чем вторая.

Ссылка на комментарий
Поделиться на другие сайты

Случайные числа

 

Для получения случайных чисел служит функция rand(). Параметров у нее нет. Она возвращает случайное число от 0 до значения констаны RAND_MAX. Как правило, эта константа равна 32767 (2 в 15-степени минус 1). Функция rand() (как и константа RAND_MAX) описана в файле stdlib.h, так что не забудьте подключить его:

#include <stdlib.h>

 

Вот пример использования функции rand():

int k;

k=rand();

 

Обратите внимание, что функция rand() будет постоянно возвращать одну и ту же последовательность случайных чисел. Это очень удобно на этапе отладки программы - если программа выдает ошибку, то эту ошибку легче воспроизвести при одних и тех же случайных числах. Реальная же программа должна, как правило, возвращать разные последовательности случайных чисел. Это делаем через функцию srand, которая принимает целый параметр, определяющий, какая конкретно последовательность случайных чисел у нас будет выдаваться функцией rand. Функцию srand достаточно вызвать только один раз в начале программы. Правда, в srand мы должны в качестве параметра подставить случайное число, но его можно получить, например, из текущего времени. Вот пример:

#include <time.h>

...

srand((unsigned)time(NULL));

cout<<rand()<<"\n";

Ссылка на комментарий
Поделиться на другие сайты

Рекурсивные функции

 

Функция может вызывать сама себя. Т. е. внутри функции мы используем ее саму.

 

Вот классический пример - вычисление факториала (факториал n (обозначается как n!) - это произведение целых чисел от 1 до n. Например, 4!=24 (1*2*3*4)):

//Объявление функции.

int fact(int n)

{

if(n>1)

{

//Вызываем функцию из себя самой.

return n*fact(n-1);

}

else

{

//Факториал 1 равен 1.

return 1;

}

}

void main()

{

//Вызов функции.

cout<<fact(5);

}

 

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

 

Указанный фрагменты выведет, естественно, 120 (1*2*3*4*5).

Ссылка на комментарий
Поделиться на другие сайты

Шаблоны функций

 

Шаблоны служат для ситуции, когда у нас есть разные типы данных, с которыми мы должны работать по одному, не зависящему от этих типов данных, алгоритму. Например, метод сортировки массива не зависит от типов данных - такой алгоритм будет одинаков и для, например, чисел типа int и для чисел типа float.

 

Приведем пример использования шаблона.

 

Вот код для простейшего щаблона функции, которая из двух передаваемых в нее параметров возвращает максимальный:

#include <iostream.h>

//Объявление шаблона функции.

template <class T>

T max(T a, T b)

{

if(a>b)

{

return a;

}

else

{

return b;

}

}

void main()

{

//Использование шаблона функции для целых.

int x = 45, y = 32;

cout<<max(x, y)<<"\n"; //Выведется 45.

//Использование шаблона функции для вещественных.

float s = 4.18, t = 34.08;

cout<<max(s, t)<<"\n"; //Выведется 34.08.

 

}

 

Обратите внимание на синтаксис. Сначала мы пишем ключевое слово template и задаем формальный тип T (T - это просто произвольное имя):

template <class T>

...

 

Далее мы пишем непосредственно функцию, причем в качестве типа параметров и возвращаемого значения пишем введенный ранее формальный тип T:

T max(T a, T b)

...

 

Разумеется, количество параметров может быть любое и не все из них должны иметь тип T. То же относится и к типу возвращаемого значения - в нашем случае это тот же тип T, но в принципе тип может быть любой, хоть void.

 

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

 

Теперь пара слов о использовании шаблона. При использовании мы просто пишем имя функции (в нашем случае это max) с параметрами конкретных типов (int и float в нашем примере). Компилятор в этом месте сам сгенерирует на основании этого шаблона функцию с параметрами конкретных типов.

 

Шаблоны существую не только для функций, но и для классов. Такие шаблоны мы рассмотрим позже.

Ссылка на комментарий
Поделиться на другие сайты

Параметры командной строки

 

В программу могут передаваться параметры командной строки. Несколько примеров таких программ - это команда ping (в качестве параметра выступает ip-адрес компьютера, с которым вы хотите проверить связь), команда copy (в качестве параметра выступают имя компируемого файла и новое местоположение и имя).

 

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

 

Вот пример функции, которая выведет все свои параметры командной строки:

#include <iostream.h>

void main(int argc, char* argv[])

{

for(int i=0; i<argc; i++)

{

//Выводим имя exe-файла

//и все параметры командной строки.

cout<<argv<<"\n";

}

}

 

Тут первый параметр: argc - это общее количество параметров. При простом запуске программы (например, простым щелчком на exe-файле) он будет равен 1. Второй параметр представляет из себя массив типа char*. Тип char* - это указатели на символ, который интерпретируется как строка. Нулевой элемент в этом массиве строк - это имя самого exe-файла, первый - это первый передаваемый параметр, второй - второй передаваемый параметр (разумеется, если эти параметры вообще есть).

 

post-35276-1269236471,63.gif

 

В средах разработки часто существует возможность задать параметры командной строки в самой IDE. Вот так, например, это делается в Visual C++.NET. Из контесктного меню для проекта выбираем Properties:

 

post-35276-1269236511,3.gif

 

затем в появившемся окне Property Pages в разделе Debugging задаем Command Arguments:

 

post-35276-1269236558,23.gif

Откомпилируем и запустим нашу программу из командной строки с параметрами. Результат будет приблизительно такой:

Ссылка на комментарий
Поделиться на другие сайты

Классы

 

В ранее мы рассматривали структуры. Классы чем-то напоминают структуры - у них также внутри есть переменные разных типов. Но наряду с этими переменными у класса есть и несколько отличий, которые мы сейчас и рассмотрим на примере.

 

Вот пример класса:

#include <iostream.h>

//Объявление класса прямоугольника.

class CRect

{

float m_a, m_b; //Стороны.

public:

//Методы класса.

//Методы по чтению и записи сторон.

void SetA(float a);

void SetB(float b);

float GetA();

float GetB();

 

float GetSquare(); //Площадь.

float GetPerim(); //Периметр.

bool IsSquare(); //Не является ли прямоульник квадратом.

}; //Точка с запятой обязательна!

void main()

{

//Использование класса.

CRect r;

r.SetA(5);

r.SetB(3);

cout<<"Perimeter = "<<r.GetPerim()<<"\n";

cout<<"Square = "<<r.GetSquare()<<"\n";

if(r.IsSquare())

{

cout<<"Square\n"; //Квадрат.

}

else

{

cout<<"Not a quare\n"; //Не квадрат.

}

}

//Реализация методов класса.

//Методы по чтению и записи сторон.

void CRect::SetA(float a)

{

if(a>0)

{

m_a = a;

}

else

{

m_a = 1;

}

}

void CRect::SetB(float b)

{

if(b>0)

{

m_b = b;

}

else

{

m_b = 1;

}

}

float CRect::GetA()

{

return m_a;

}

float CRect::GetB()

{

return m_b;

}

//Площадь.

float CRect::GetSquare()

{

return m_a*m_b;

}

//Периметр.

float CRect::GetPerim()

{

return (m_a+m_b)*2;

}

//Не является ли прямоульник квадратом.

bool CRect::IsSquare()

{

return (m_a==m_b);

}

 

После запуска программы выведет, что периметр равен 16, площадь - 15 и что это - не квадрат. Этого, собственно, и следовало ожидать.

 

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

 

В методе main мы создали так называемый экземпляр класса (с именем r) - можно считать, что это конкретный прямоугольник. Экземпляр класса объявляется аналогично объявлению обычной переменной. Потом мы в main вызываем функции (методы) класса для нашего экземпляра r.

Ссылка на комментарий
Поделиться на другие сайты

Разбор первого класса

 

Итак разберем наш первый класс.

 

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

class MyClass

{

//Внутренность класса.

};

 

Тут вместо MyClass мы можем написать, разумеется, любое имя. Обратите так же внимание на точку с запятой в конце класса - она обязательна.

 

Объявление класса - это как бы конструирование нового типа данных. В C/C++ есть встроенные типы данных - int, char, float и другие. Но для реальной задачи удобнее создать свои типы, которые будет лучше моделировать поставленную задачу. Классы как раз для этого и предназначены.

 

Теперь несколько слов о том, что может находиться внутри класса. А именно, там могут находиться переменные разных типов и функции (они же методы) класса. Переменные могут быть самых разных типов - в том числе и экземпляры других классов (и даже экземпляры того же самого класса). Вообще внутренность класса делится на 3 части - public (доступна всем), private (доступна только самому классу) и protected (доступна классу и его потомкам. Слово private можно не писать - оно действует по умолчанию. Т. е. наши переменные m_a и m_b нахадятся в private части класса:

class CRect

{

float m_a, m_b; //Стороны.

...

 

Зачем мы поместили m_a и m_b в private часть класса? Так как на их значения существуют ограничения - а именно они не могут быть отрицательные. Поэтому для доступа к этим переменным мы добавили по две функции GetA/B - для чтения и SetA/B - для записи:

...

void SetA(float a);

void SetB(float b);

float GetA();

float GetB();

...

 

Эти функции мы объявили, разумеется, в public части класса. Обратите внимание, что функции мы только объявили, а реализацию функций мы пишем вне класса:

...

void CRect::SetA(float a)

{

if(a>0)

{

m_a = a;

}

else

{

m_a = 1;

}

}

...

 

При этом мы перед именем функции пишем обязательно имя класс с двойным двоеточием (для того, что бы показать, что эта функция именно из нашего класса):

void CRect::SetA(...)

...

 

Функции SetA/B мы написали так, что они позволяют записать только положительно значение. Если в такую функцию мы передадим для стороны отрицательное значение, то запишется не оно, а единица.

 

С функциями, вычисляющими площадь, периметр и выясняющими, не есть ли наш прямоугольник квадратом, тоже все ясно - они используют соответствующие формулы из математики и возвращают нужное значение посредством return.

 

В функции main мы создаем экземпляр нашего класса:

void main()

{

//Использование класса.

CRect r;

...

 

и затем с этим экземпляром работаем - устанавливаем для него значения сторон A и B, считаем периметр и др.:

...

r.SetA(5);

r.SetB(3);

cout<<"Perimeter = "<<r.GetPerim()<<"\n";

cout<<"Square = "<<r.GetSquare()<<"\n";

...

 

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

r.SetA(5);

 

Можно в программе объявить несколько экземпляров класса или даже массив:

CRect w, v;

CRect z[5];

 

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

Ссылка на комментарий
Поделиться на другие сайты

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

 

Конструкторы и деструкторы - это специальные методы класса. Это надо понять в первую очередь. Разумеется, эти методы обладают целым рядом особенностей (именно по этому они и выделены в специальную группу). Сейчас об этих особенностях и поговорим.

 

Первое. В отличие от других методов они должны называться особым образом. Если обычные методы могут называться как угодно, то имя констуктора должно совпадать с именем класса, а имя деструктора - с именем класса с приписанной в начале тильдой. Например, если класс называется CRect, то конструктор этого класса обязан называться тоже CRect, а деструктор - ~CRect.

 

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

 

Третье. Ни конструктор, ни деструктор не возвращают никакого значения (даже типа void). Это означает, в частности, что при обяъвлении конструтора и деструктора в классе мы перед ними не пишем ни какой тип.

 

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

 

Вот пример на все вышесказанное :

class CRect

{

float m_a, m_b; //Стороны.

public:

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

CRect(); // Конструктор без параметров.

CRect(float a. float b); // Конструктор с двумя параметрами.

~CRect(); // Деструктор.

...

};

...

// Реализация конструкторов и деструкторов.

CRect::CRect()

{

// Задание стандартных (нулевых) значений.

m_a = 0;

m_b = 0;

}

CRect::CRect(float a. float b)

{

// Задание значений, задаваемых параметрами.

m_a = a;

m_b = b;

}

CRect::~CRect()

{

// Просто вывод некоторой надписи.

cout<<"Destructor\n";

}

А вот так можно использовать класс в функции main:

void main()

{

//Использование класса.

 

CRect r; // Вызов конструктора без параметров.

cout<<"Perimeter = "<<r.GetPerim()<<"\n"; // Выведется 0.

cout<<"Square = "<<r.GetSquare()<<"\n"; // Выведется 0.

 

CRect r1(2, 3); // Вызов конструктора с параметрами.

cout<<"Perimeter = "<<r1.GetPerim()<<"\n"; // Выведется 10.

cout<<"Square = "<<r1.GetSquare()<<"\n"; // Выведется 6.

 

// В этом месте вызовутся 2 деструктора - для переменных r и r1.

// Соответственно, на консоль выведется два раза слово "Destructor".

}

Ссылка на комментарий
Поделиться на другие сайты


×
×
  • Создать...