Основные типы данных:
Кроме них существуют: структуры, объединения, объекты классов, перечислимый тип (enum) и пустой тип (void). Тип void используется для объявления функций, не возвращающих никакого значения, а также для объявления указателей на значение типа void. Такие указатели могут быть преобразованы к указателям на любой другой тип. В языке C++ нет специальных типов для массивов и строк.
Преобразования типов. В языке С++ предусмотрено автоматическое и явное преобразование типов. Автоматическое приведение типов имеет следующую иерархию. Если тип одного операнда long double, другой преобразуется в long double. Если тип одного операнда double, другой операнд преобразуется в double; или float, другой преобразуется в float; Иначе преобразуются оба операнда: char, signed, char, unsigned char, short int и unsigned short int преобразуются в int, если int может представить все значения исходных типов, иначе они преобразуются в unsigned int; bool преобразуется в int. Если тип одного операнда unsigned long, другой операнд преобразуется к типу unsigned long: если тип одного операнда long int,а другого unsigned int, то если long int может представить все значения типа unsigned int, unsigned int преобразуется в long int, иначе оба операнда преобразуются в unsigned long int; иначе, если тип одного операнда long int, другой операнд преобразуется в long int, иначе, если тип одного операнда unsigned int другой операнд преобразуется в unsigned int; иначе оба операнда имеют тип іnt.
Пример использования автоматического преобразования типов:
#include <iostream>
using namespace std;
int main()
{ int sajen = 7;
float koeff = 2.1336F;
double rasst = sajen * koeff; // автоматическое приведение к типу double cout << "Расстояние " << sajen << " равно " << rasst << " м" << endl; return 0 }
Для явного преобразования типов используются операции:
static_cast осуществляет преобразование родственных типов (указателя на один тип к указателю на другой тип из той же иерархии классов, целый тип в перечисление или тип с плавающей точкой в интегральный). reinterpret_cast управляет преобразованиями между несвязанными типами, (целых в указатели или указателей в другие (несвязанные) указатели).
Преобразование const_cast аннулирует действие модификатора const.
Операции приведения типов имеют следующий синтаксис:
Пример использования явного преобразования типов:
#include <iostream>
using namespace std;
int main()
{ int intVar = 1500000000;
intVar = (static_cast(intVar)*10)/10; //явное приведение к double
cout << "Значение intVar равно " << intVar << endl;
return 0; }
Для ввода/вывода в С++ используют потоки ввода и вывода. Для этого необходимо включить заголовочный файл <iostream>. Для ввода используется операция >>, для вывода — операция <<. Компилятор определяет тип вводимой/выводимой переменной и соответствующим образом форматирует её. Если при вводе или выводе произошла ошибка, в переменной состояния потока устанавливается соответствующий флаг. Проверить его значение можно с помощью функции fail. Использования потоков ввода-вывода:
#include <iostream>
using namespace std;
int main()
{ int ftemp;
cout << "Введите температуру по Фаренгейту: ";
cin >> ftemp;
if (cin.fail()) //Обнаружение ошибок
cout << "Произошла ошибка при вводе" << endl;
int ctemp = (ftemp‐32)*5 / 9;
cout << "Температура no Цельсию равна " << ctemp << endl;
return 0;}
Манипуляторы ввода-вывода управляют форматом вводимого/выводимого значения. Это функций, которые вставляются между вводимыми/выводимыми значениями и изменяют состояние потока. Для использования манипуляторов необходимо включить заголовочный файл <iomanip>.
Стандартные манипуляторы ввода-вывода:
использования манипулятора setw:
#include <iostream>
#include <iomanip> // для использования setw
using namespace std;
int main()
{ long nas1 = 8425785, nas2 = 4761, nas3 = 9761;
cout << setw(9) << "Город" << setw(12) << "На‐ селение" << endl << setw(9) << "Москва" << setw(12) << nas1 << endl << setw(9) << "Киров" << setw(12) << nas2 << endl << setw(9) << "Угрюмовка" << setw(12) << nas3 << endl;
return 0; }
3. Операции отношения. Логические операции. Приоритеты операций С++.
Операции отношения используются для сравнения значений в условных выражениях. Значения могут быть как стандартных типов языка C++, так и типов, определяемых пользователем (в таком случае оператор должен быть переопределен). Сравнение устанавливает одно из трех возможных отношений между переменными: равенство, больше, меньше. Результатом сравнения является значение истина(1) или ложь(0). Несмотря на то, что в большинстве случаев, для представления истинного значения используют 1, любое отличное от нуля число будет воспринято как истинное, операция эквивалентности, в отличие от операции присваивания, обозначается с помощью двойного знака равенства. Примеры условных выражений: a>0; num<=100; ‘c’== ‘C’; ‘c’!=‘C’.
Логические операции — операции, позволяющие производить действия над булевыми переменными, то есть переменными, обладающими только двумя значениями — истина и ложь.
Приоритет_операций.
4.Циклы и ветвления. Иногда необходимо повторять одно и то же действие несколько раз подряд. Для этого используют циклы.Если мы знаем точное количество действий (итераций) цикла, то можем использовать цикл for.Итерацией цикла называется один проход этого циклаСчетчик цикла — это переменная, в которой хранится количество проходов данного цикла.Описание синтаксиса1. Сначала присваивается первоначальное значение счетчику, после чего ставится точка с запятой.2. Затем задается конечное значение счетчика цикла. После того, как значение счетчика достигнет указанного предела, цикл завершится. Снова ставим точку с запятой.3. Задаем шаг цикла. Шаг цикла — это значение, на которое будет увеличиваться или уменьшаться счетчик цикла при каждом проходе.Пример кода:#include <iostream>using namespace std;int main(){int i; // счетчик циклаint sum = 0; // сумма чисел от 1 до 1000.setlocale(0, "");for (i = 1; i <= 1000; i++) // задаем начальное значение 1, конечное 1000 и задаем шаг цикла - 1. {sum = sum + i;}cout << "Сумма чисел от 1 до 1000 = " << sum << endl;return 0;} Цикл while Когда мы не знаем, сколько итераций должен произвести цикл, нам понадобится цикл while или do...while.#include <iostream>using namespace std;int main(){setlocale(0, "");int i = 0; // инициализируем счетчик цикла.int sum = 0; // инициализируем счетчик суммы.while (i < 1000){i++;sum += i;}cout << "Сумма чисел от 1 до 1000 = " << sum << endl;return 0;} Цикл do while Цикл do while очень похож на цикл while. Единственное их различие в том, что при выполнении цикла do while один проход цикла будет выполнен независимо от условия.#include <iostream>using namespace std;int main (){setlocale(0, "");int i = 0; // инициализируем счетчик цикла.int sum = 0; // инициализируем счетчик суммы.do {// выполняем цикл.i++;sum += i;} while (i < 1000); // пока выполняется условие.cout << "Сумма чисел от 1 до 1000 = " << sum << endl;return 0;}Ветвления. Оператор if Оператор if служит для того, чтобы выполнить какую-либо операцию в том случае, когда условие является верным.Каждому оператору if соответствует только один оператор else. Совокупность этих операторов — else if означает, что если не выполнилось предыдущее условие, то проверить данное. Если ни одно из условий не верно, то выполняется тело оператора else.#include <iostream>using namespace std;int main(){setlocale(0, "");double num;int k; cout << "Введите произвольное число: "; cin >> num;if (num < 10) { // Если введенное число меньше 10.cout << "Это число меньше 10." << endl;k = 1;} else if (num == 10) {cout << "Это число равно 10." << endl;k = 2;} else { // иначеcout << "Это число больше 10." << endl;k = 3;}cout << "k = " << k << endl;return 0;}
5. Синтаксис определения структуры и структурной переменной. Доступ к полям структуры. Присвоение структурных переменных. Определение структуры начинается с ключевого слова struct, затем следует имя структуры. Объявления полей структуры заключены в фигурные скобки. После закрывающей фигурной скобки следует точка с запятой (;). Далее рассмотрим определение переменной. Переменная типа, определенного пользователем, объявляется двумя способами: 1) при определении структуры struct part { int modelnumber; int partnumber; float cost; } 2) после определения структуры part p1, p2; Определение переменной означает, что под эту переменную выделяется память. Под структурную переменную всегда отводится столько памяти, сколько достаточно для хранения всех ее полей. Доступ к полям структуры. Когда структурная переменная определена, доступ к ее полям возможен с применением операции точки. В следующей строчке первому из полей структуры part присваивается значение при помощи оператора «=»: p1.modelnumber = 6244; Поле структуры идентифицируется с помощью трех составляющих: имени структурной переменной p1, операции точки (.) и имени поля modelnumber. Присваивание структурных переменных: p2=p1; Значение каждого поля переменной p1 присваивается соответствующему полю переменной p2. Нельзя присваивать переменные разных структур друг другу, даже если шаблоны структур совпадают.
6. Синтаксиз опредедления и инициализации указателя на структуру. Работа с полями структуры через указатель. Указатели - это переменные, в которых хранится адрес других переменных. Используются два основных оператора: * — показывает, кто живет в этом номере (показывает значение переменной по заданному адресу). Если вы используете оператор *, то вы занимаетесь операцией разыменование указателя. Так по другому называется использование оператора *. & — говорит, по какому адресу проживает этот человек (показывает адрес переменной). При объявлении указателя на структуру, как и в случае создания указателей на значения базовых типов, указывается тип структуры, а перед именем переменной указателя ставится оператор *. Этот же оператор используется для получения доступа к переменной структуры по указателю на эту переменную. Кроме того, через указатель на структуру можно обращаться непосредственно к полям структуры, для чего используют оператор -> (стрелка, состоит из двух символов - и >). Например, если в программе определен указатель на переменную структуры, у которой есть поле, то доступ к этому полю можно получить с помощью инструкции указатель->поле. Пример: #include <iostream> using namespace std; struct Numbers {int integer; double real; char symbol;}; void show(Numbers x) //вертуальная функция в этой прогрумме нужна, для вывода {cout << "Integer: "<<x. integer << endl; cout << "Real: "<<x. real << endl; cout << "Symbol: " << x. symbol << endl<<endl;} int main() {Numbers a,b; Numbers *p,*q; p=&a; q=&b; p->integer=1; p->real=2.5; p->symbol= 'a'; (*q).integer=2; (*q).real=5.1; (*q).symbol='b'; show(a); show(*q); return 0;} Работа с полями структуры через указатель. Пример: #include <iostream> using namespace std; truct Spisok {char name[100]; char book[30];}; int main () {Spisok bible; cin>>bible.book; cin>>bible.name; Spisok* bpointer; //"bpointer" - указатель на структуру bpointer = &bible; cout << bpointer->book << " "<< bpointer->name; /*"bpointer ->book" - обращение к полю структуры через указатель на структуру.*/ return 0;}
7.Синтаксис перечисления. Синтаксис объединения. Особенности размещения в памяти и доступности элементов перечисления и объединения. Перечисляемый тип задаёт тип, который является подмножеством целого типа. Синтаксис:enum [<тег>] {<список перечисления>} <описатель>[, <описатель>...];enum <тег> <описатель> [,<описатель>...];Тег предназначен для различения нескольких перечислимых типов, объявленных в одной программе.Список перечисления содержит одну или более конструкций вида:<идентификатор>[=<константное выражение> ]Конструкции в списке разделяются запятыми. Каждый идентификатор именует элемент списка перечисления. По умолчанию, если не задано константное выражение, первому элементу присваивается значение 0, следующему элементу — значение 1 и т. д.Пример// объявление перечисляемого типаenum days_of_week { Sun, Mon, Tue, Wed, Thu, Fri, Sat };int main(){days_of_week day1, day2; // определения переменных, хранящих дни неделиday1 = Mon; // инициализация переменныхday2 = Thu; int diff = day2 — day1; // арифметическая операцияcout << "Разница в днях: " << diff << endl; if(day1 < day2) // сравнениеcout << "day1 наступит раньше, чем day2\n";return 0;} Объединения - это объект, позволяющий нескольким переменным различных типов занимать один участок памяти. Объявление объединения похоже на объявление структуры: union union_type { int i; char ch; };Как и для структур, можно объявить переменную, поместив ее имя в конце определения или используя отдельный оператор объявления. Для объявления переменной cnvt объединения union_type следует написать: union union_type cnvt;Объединение применяется для следующих целей:- инициализации используемого объекта памяти, если в каждый момент времени только один объект из многих является активным;- интерпретации основного представления объекта одного типа, как если бы этому объекту был присвоен другой тип.Особенности размещения в памяти и доступности элементов перечисления и объединения?
8.Определение функции. Передача аргументов и возврат значений по значению, ссылке и через указатель. Аргументы по умолчанию. Константные аргументы функции. В C++, функции не должны быть определены до момента их использования, но они должны быть ранее объявлены. Но даже после всего этого, эта функция должна быть определена. После этого прототип функции и ее определение связываются, и эта функция может быть использована.Если функция ранее была объявлена, она должна быть определена с тем же возвращаемым значением и типами данных, в противном случае, будет создана новая, перегруженная функция. Имена параметров функции не должны быть одинаковыми.void aFunc(int& a, const int& b); // прототип функции int main() { int alpha = 7; int beta = 11; aFunc(alpha, beta); return 0; } void aFunc(int& a, const int& b) // определение функции { a = 107; // корректно b = 111; /* ошибка при попытке изменить кон‐ стантный аргумент*/ }В языке С++ существует 3 способа передачи аргументов в функцию: • передача аргумента по значению; • передача с использованием указателя на аргумент; • передача аргумента по ссылке. Передача по значению. Данный метод копирует содержимое аргумента в формальный параметр подпрограммы. Изменения, сделанные в параметре, не влияют на значение переменной, используемой при вызове. Передача по ссылке. В данном методе копируется адрес аргумента. В подпрограмме адрес используется для доступа к настоящему аргументу, используемому при вызове. То есть, изменения, сделанные в параметре, влияют на содержимое переменной, используемой при вызове. Передача через указатель. В случае, если функция должна менять свои аргументы, можно использовать указатели. Указатели также передаются по значе- нию, внутри функции создается локальная переменная-указатель. Но, так как этот указатель инициализируется адресом переменной из вызываемой программы, то эту переменную можно менять, ис- пользуя этот адрес. Если передавать параметры через указатель код функции выглядит так:mul5(int *x){*x = *x * 5;}Вызов:int var=10;mul5(&var); // Здесь символ & обозначает операцию взятия адреса переменной аргументы по умолчанию. Аргументы по умолчанию. В языке С++ можно задавать так называемые параметры функции по умолчанию. Если в объявлении формального параметра задано выражение, то оно воспринимается как умолчание этого параметра. Все последующие пара- метры также должны иметь умолчания. Умолчания параметров подставляются в вызов функции при отсутствии в нём последних по списку параметров. Примером аргументов по умолчанию являются переменные x и у функции sum_cvad #include using namespace std; inline float sum_cvad(float x = 0.0F, float y = 0.0F) { return (x * x + y * y); } int main() { float a, b; cout << "Введите два числа "; cin >> a >> b; cout << "a^2 + b^2 = " << sum_cvad(a,b) << endl; cout << "a^2 = " << sum_cvad(a) << endl; /*верно, т.к. по умолчанию второй аргумент равен нулю.*/ return 0; } Константные аргументы функции применяются, когда нужно передать аргумент по ссылке и при этом запретить его изменение. В списке аргументов объявления/определения нужно поставить ключевое слово const перед соответствующим аргументом. В списке аргументов объявления/определения нужно поставить ключевое слово const перед соответствующим аргументом. Пример: void aFunc(int& a, const int& b); // прототип функции int main() { int alpha = 7; int beta = 11; aFunc(alpha, beta); return 0; } void aFunc(int& a, const int& b) // определение функции { a = 107; // корректно b = 111; /* ошибка при попытке изменить кон‐ стантный аргумент*/ }
9. Перегруженные функции. Встраиваемые функции. Рекурсивные функции. Перегруженные функции — это функции с одним именем, но с разными типами аргументов. Их используют, когда несколько функций выполняют одинаковые действия, только над разными типами. Перегруженные функции могут отличаться не только типами аргументов, но и их количеством, но они должны возвращать значение одного типа. Пример #include <iostream> #include <cmath> using namespace std; int summa(int& a, int& b) { cout << "Складываем два целых числа "; return a+b; } int summa(int& a, int& b, int&c) { cout << "Складываем три целых числа "; return a+b+c; } int summa(float& a, float& b) { cout << "Складываем два дробных числа "; return floor(a+b); } //выделение целой части int main() { int a, b, c; float d, e; cout << "Введите два целых числа "; cin >> a >> b; cout << a <<" + "<< b <<" = "<< summa(a,b) << endl; cout << "Введите еще одно целое число "; cin >> c; cout << a <<" + "<< b <<" + "<< c <<" = "<< summa(a,b,c) <<endl; cout << "Введите два дробных числа "; cin >> d >> e; cout << d <<" + "<< e <<" = "<< summa(d,e) << endl; return 0; } Рекурсивные функции. Ситуацию, когда функция тем или иным образом вызывает саму себя, называют рекурсией. Рекурсия, когда функция обращается сама к себе непосредственно, называется прямой; в противном случае она называется косвенной. Все функции языка С++ (кроме функции main) могут быть использованы для построения рекурсии. В рекурсивной функции обязательно должно присутствовать хотя бы одно условие, при выполнении которого последовательность рекурсивных вызовов должна быть прекращена. Рекурсивные функции обычно выполняются медленнее, чем их нерекурсивные (итеративные) аналоги. Это связано с затратами времени на вызов функции. Однако, как правило, они компактнее и понятнее. Пример. #include <iostream> long factor (int n) {if (n<1) return 1; else return n*fact(n-1); int main() {std::cout<< "Факториал числа 5 равен " << factor(5) << std::endl; return 0;} Встраиваемые
Функция, определенная в теле объявления класса, является встроенной. Встраиваемые функции нужны для сокращения времени работы программы. Пример #include <iostream> using namespace std; inline float sum_cvad(float x = 0.0F,float y = 0.0F) {return (x * x + y * y);} int main() {float a, b; cout «"Введите два числа "; cin » a » b; cout «"a^2 + b^2 = " «sum_cvad(a,b) «endl; cout «"a^2 = " «sum_cvad(a) «endl; /*верно, т.к. по умолчанию второй аргумент равен нулю.*/ return 0; }
10.Область видимости и класс памяти. У каждой функции есть своя область видимости. В область видимости функции входят все глобальные переменные и переменные, объявленные в этой функ- ции. Глобальные переменные — это переменные, которые определены за пределами любой функции. Глобальные переменные существуют с того момента как они встретились в коде и до конца программы. Если глобальную переменную объявить после какой-нибудь функции, то в этой функции данную переменную нельзя будет использовать. Локальные переменные объявлены внутри функций и видны только в них самих. Обычные локальные переменные, когда функция завершается, уничтожаются. При каждом выполнении функции они создаются заново. Статические переменные определяются только один раз — когда функция вызывается в первый раз. Когда функция заканчивает выполнение операторов, статические переменные остаются в па- мяти. Когда функция снова вызывается, она продолжает их использовать. Например, в листинге 1 есть две локальные переменные а, одна принадлежит функции main, другая — pass_by_value. #include <iostream> using namespace std; void pass_by_value (int a) {a ++; cout<<"В функции pass_by_value a = " << a << endl; } void pass_by_pointer (int* a) {*a +=2; cout << "В функции pass_by_pointer a = " << *a << endl; } void pass_by_reference (int& a) {a +=3; cout << "В функции pass_by_reference a = " << a << endl; } int main() {int a; cout << "Введите перевенную "; cin >> a; cout << "Вы ввели " << a << endl; pass_by_value (a); cout << "Сейчас в функции main переменная a = " << a << endl; pass_by_pointer (&a); cout << "Сейчас в функции main переменная a = " << a << endl; pass_by_reference (a); cout << "Сейчас в функции main переменная a = " << a << endl; return 0; } 11.Объявление и инициализация одномерного и многомерного массива. Работа с элементами массива через указатель Массив – это набор переменных одного типа, имеющих одно и то же имя. Доступ к конкретному элементу массива осуществляется с помощью индекса. В языке С все массивы располагаются в отдельной непрерывной области памяти. Первый элемент массива располагается по самому меньшему адресу, а последний – по самому большому. Массивы могут быть одномерными и многомерными.Общая форма объявления одномерного массива имеет следующий вид:тип имя_переменной [размер]; Инициализация: int mas={1, 2, 3, 4, 5} Объявление многомерного массива: const unsigned int DIM1 = 3;const unsigned int DIM2 = 5;int ary[DIM1][DIM2]; Инициализация многомерного массива: const unsigned int DIM1 = 3;const unsigned int DIM2 = 5;int ary[DIM1][DIM2] = {{ 1, 2, 3, 4, 5 },{ 2, 4, 6, 8, 10 },{ 3, 6, 9, 12, 15 }}; Работа с элементами массива через указатели Допустим, что ptr_ar указывает на первый элемент массива array. Тогда для работы с элементами массива можно пользоваться следующей записью:int *ptr_ar = array; ptr_ar[0] = 10; ptr_ar[1] = 20;т.е. доступ к элементам массива осуществляется по его индексу.
12. Передача массивов в функцию. Возвращение массива функцией. Чтобы передать массив в функцию, ей надо сообщить адрес начала массива и количество его элементов. Это можно сделать при помощи двух параметров. Пример. Определить функцию, которая возвращает сумму всех элементов массива. void display(int num[10]) { int i; for (i=0; i<< num[i]; } Когда параметром является двумерный массив, его вторая размерность обязательно указывается в объявлении функции float a[ ][4] Объявление параметра как float a[ ][ ] недопустимо. Нет ничего странного в том, что компилятору требуется вторая размерность, ведь именно она определяет размер тех одномерных массивов, которые составляют двумерный. Пример. Определить функцию, которая распечатывает двумерный массив а[3][4] в виде матрицы. void print (float a[] [4], int n) { for (int i = 0; i < n; i++) {for (int j = 0; j < 4; j++) cout «a[i][j] «" "; cout «endl;}} Дело в том что в C++ в функцию можно передать только указатель (или ссылку) на массив, соответственно вы всегда будете работать с исходным массивом, а не с его копией (и вернете также указатель на исходный массив): int* Func(int *Array) {for(i = 0; i < 3; i++) {Array[i]++;} return Array;} int func(int i, int * mas_old, int * mas_new); int main() {int mas1[]={1, 2, 3, 4}; int mas2[4]; func(4, mas1, mas2); return 0;}
13. Принципы объекто-ориентированного программирования. Инкапсуляция.Наследование.Полипорфизм. Объектно-ориентированное программирование строится на 3-ех принципах: Инкапсуляция Наследование Полипорфизм Инкапсуляция: Проектирование программных и технических систем базируется на том условии, что никакая подсистема данного уровня не должна зависеть от устройства любой другой подсистемы этого уровня. Такая независимость внутреннего устройства одного объекта от внутреннего устройства другого называется инкапсуляцией. В объектно-ориентированном программировании принцип инкапсуляции используется для изоляции класса от остальных частей программы, чтобы сделать его самодостаточным для решения конкретной задачи. 1.Инкапсуляция в ООП – сосредоточение и сокрытие атрибутов и методов в классе или объекте. Можно осуществлять на 2-х уровнях – класса и объекта. 2. Смысл: инкапсуляция означает, что реализация атрибутов и методов скрыта от пользователя объекта или класса. 3. Цель: организовать доступ пользователя к атрибутам и методам так, чтобы предотвратить несанкционированное использование. 4. Инкапсуляция является развитием принципа модульности в построении ПО. 5. Защита от ошибок программиста заключается в неразрешенных объектах, способах использования методов (атрибутов). 6. Сокрытие позволяет программисту изменять реализацию класса, не изменяя его возможностей для пользователя (не менять интерфейс). 7. Развитие методов модульного программирования. 8. К переменной определенного типа нельзя применять действия, непредусмотренные этим типом; правила видимости типов; Скрывать можно и атрибуты, и методы. Пример class A {public: int a, b; //данные открытого интерфейса int ReturnSomething(); //метод открытого интерфейса private: int Aa, Ab; //скрытые данные void DoSomething();}; //скрытый метод //наряду с private и public есть еще protected Наследование: Принцип наследования оперирует с понятиями «предок - потомок» и предусматривает расширение набора свойств наследника за счет принятия всех свойств предка. Любой класс может быть порожден от другого класса. Для этого при его объявлении указывается имя класса-родителя. сlass Имя: МодификаторДоступа ИмяБазовогоКласса Порожденный класс автоматически наследует поля, методы и свойства своего родителя и может добавлять их новыми. Таким образом, принцип наследования обеспечивает поэтапное создание сложных классов и разработку собственных библиотек классов. При общем наследовании порожденный класс имеет доступ к наследуемым членам базового класса с видимостью public и protected. Члены базового класса с видимостью private – недоступны. Пример class A{}; class B: public A //класс B наследуется из класса A {}; A obj1; //obj1 есть объект класса A B obj2; //obj2 есть объект класса B void main(){return;}
Полипорфизм: Полиморфизм — термин, используемый для описания процесса, при котором различные реализации функций могут быть доступны с использованием одного имени. Это означает, что основной класс операций может быть оформлен в одном стиле, хотя конкретные действия могут быть различны. В С++ полиморфизм поддерживается и во время компиляции — перегрузка функций и операторов, и во время выполнения программы — использование указателей на базовые классы и виртуальных функций. (Полиморфизм - это когда наследуемые классы или просто различные классы имеют одинаковые методы, но с различной реализацией) Целью полиморфизма является использование одного имени для задания общих для класса действий, причем каждый объект или класс иерархии имеет возможность по-своему реализовать это действие своим собственным, подходящим для него, кодом. Таким образом, полиморфизм является свойством классов решать схожие по смыслу проблемы разными способами./*КЛАСС-РОДИТЕЛЬ*/class Mammal{public: virtual void Speak() {cout<<"Mammal Speakn";} };//Виртуальный метод. Звук неизвестного млекопитающего/*СОЗДАЕМ ПОДКЛАСС МЛЕКОПИТАЮЩЕГО*/ class Dog:public Mammal{ public: void Speak() {cout<<"GavGavn";} };//Виртуальный метод. Собака лает /*СОЗДАЕМ ПОДКЛАСС МЛЕКОПИТАЮЩЕГО*/class Cat:public Mammal {public: void Speak() {cout<<"Meown";} };//Виртуальный метод. Кот мяукает/*СОЗДАЕМ ПОДКЛАСС МЛЕКОПИТАЮЩЕГО*/class Pig:public Mammal {public:void Speak() {cout<<"HruHrun";} }; //Виртуальный метод. Свинья хрюкает
14. Класс и объекты в языке С++. Члены класса. Определение класса (поля, методы, доступ к членам класса). Определение методов в классе и вне класса. Определение класса (поля, методы, доступ к членам класса). Классы являются основой С++. Для того чтобы определить объект, нужно сначала определить его форму с помощью ключевого слова class. Объект находится в таком же отношении к своему классу, в каком переменная находится по отношению к своему типу. Объект является экземпляром класса, так же, как и автомобиль — колесного средства передвижения. Класс может содержать приватную часть (private) и общую (public). Приватные элементы не могут использоваться никакими функциями, не являющимися членами класса. Также можно определить и приватные функции, которые могут вызываться только другими функциями — членами класса. Это — один из путей реализации принципа инкапсуляции. По умолчанию все элементы класса приватные, поэтому ключевое слово private можно опустить. Поле класса — это данные, содержащиеся внутри класса. Методы класса — это функции, входящие в состав класса:
Определение методов в классе и вне класса. Доступ к методам класса возможен только через конкретный объект этого класса. Для этого используют операцию точки, т. е. операцию доступа к члену класса (.). пример определения метода в классе
// детали изделия в качестве объектов #include <iostream> using namespace std; class part // определение класса { private: int modelnumber; // номер изделия int partnumber; // номер детали float cost; // стоимость детали public: // установка данных void setpart(int mn, int pn, float c) { modelnumber = mn; partnumber = pn; cost = c; } void showpart() // вывод данных { cout << "модель " << modelnumber; cout << ", деталь " << partnumber; cout << ", стоимость $" << cost << endl; } }; int main() { part part1; // определение объекта // класса part part1.setpart(6244, 373, 217.55F); // вызов метода part1.showpart(); // вызов метода return 0; } Результат: Модель 6244, деталь 373, цена $217.55
Метод класса не обязательно определять внутри самого класса. Для этого определение класса должно содержать прототип функции. В таком случае форма записи, что устанавливает взаимосвязь функции и класса, к которому относится эта функция, имеет вид
Символ (::) является знаком операции глобального разрешения. А имя класса, операция разрешения и имя функции вместе называют — квалификационным именем функции.
Объекты как аргументы методов и доступ к их членам. Объекты можно передавать в функции в качестве аргументов точно так же, как передаются данные других типов. Следует помнить, что С++ методом передачи параметров, по умолчанию является передача объектов по значению. Это означает, что внутри функции создается копия объекта — аргумента, и эта копия, а не сам объект, используется функцией. Следовательно, изменения копии объекта внутри функции не влияют на сам объект. Можно передать параметр объекта и по ссылке, т. е. передать адрес объекта. Тогда изменения, произведенные функцией в объекте, могут изменить этот объект. При передаче в качестве параметра функции по значению объекта, как и при передаче простой переменной, произойдет создание копии объекта, тем самым вызовется конструктор, а затем деструктор
class OBJ { int i; public: void set_i(int x) {i=x;} void out_i{cout<<i<<endl;}};
void my_function(OBJ x); // прототип int main(void) { OBJ A; A.set_i(10); my_function(A); A.out_i(); return 0; }
void my_function(OBJ x) { x. out_i(); // вывод x = 10 x. set_i(100);// изменение x x. out_i();}// вывод x=100
Каждый вызов метода класса обязательно связан с конкретным объектом этого класса (исключением является вызов статической функции). Метод может прямо обращаться по имени к любым, открытым и закрытым членам этого объекта. Кроме этого, метод имеет непрямой (через операцию точки(.)) доступ к членам других объектов своего класса; последние выступают в качестве аргументов метода.
15.Конструкторы и деструкторы. Конструктор копирования по умолчанию. Конструкторы и деструкторы. Необходимость инициализации является общим требованием, поэтому С++ предоставляет возможность делать это автоматически при объявлении объекта. Эта автоматическая инициализация реализуется использованием функции, называемой конструктором. Конструктор — специальная функция, являющаяся членом класса и имеющая то же имя. Наиболее часто возлагаемая на конструктор задача — это инициализация полей объекта касса. Однако инициализация не проводится в теле конструктора. Инициализирующее значение расположено в скобках после имени поля. И если необходимо инициализировать сразу несколько полей, то значения разделяются запятыми и образуется список инициализации: someClass(): m1(0), m2(10) {/*пустое тело*/} Нельзя вызывать функцию конструктора в явном виде. Она может иметь параметры, может быть перегруженной. Если в классе не объявлен ни один конструктор, то компилятор сам создает конструктор класса. Во время создания объекта, при выделении памяти вызывается конструктор, а для освобождения памяти из-под объекта, т. е. при прекращении действия объекта, выполняется деструктор. Он имеет такое же имя, как и класс, и перед ним ставится знак тильды (~). Важно запомнить: -конструктор и деструктор, мы всегда объявляем в разделе public; -при объявлении конструктора, тип данных возвращаемого значения не указывается, в том числе — void!!!; -у деструктора также нет типа данных для возвращаемого значения, к тому же деструктору нельзя передавать никаких параметров; -имя класса и конструктора должно быть идентично; -имя деструктора идентично имени конструктора, но с приставкой ~; В классе допустимо создавать несколько конструкторов, если это необходимо. Имена, согласно пункту 2 нашего списка, будут одинаковыми. Компилятор будет их различать по передаваемым параметрам (как при перегрузке функций). Если мы не передаем в конструктор параметры, он считается конструктором по умолчанию; Обратите внимание на то, что в классе может быть объявлен только один деструктор; # include <iostream> using namespace std; class AB //класс{ private: int a; int b; public:AB(int A, int B) //эти параметры мы передадим при создании объекта в main{a = A;//присвоим нашим элементам класса значения параметровb = B;cout << "Тут сработал конструктор, который принимает параметры: " << endl;//и здесь же их отобразим на экранcout << "a = " << a << endl;cout << "b = " << b << endl << endl;} void setAB(){cout << "Введите целое число а: ";cin >> a;cout << "Введите целое число b: ";cin >> b;} void getAB(){cout << "a = " << a << endl;cout << "b = " << b << endl << endl;}~AB() // это деструктор. не будем заставлять его чистить память, пусть просто покажет где он сработал{cout << "Тут сработал деструктор" << endl;}}; int main(){ setlocale (LC_ALL, "rus"); AB obj1(100, 100); //передаем конструктору параметрыobj1.setAB(); //присвоим новые значения переменнымobj1.getAB(); //и выведем их на экранAB obj2(200, 200);} //передаем конструктору параметрыХочется еще добавить, что, как и обычным функциям, мы можем передавать конструктору параметры. Через параметры, конструктору можно передавать любые данные, которые будут необходимы при инициализации объектов класса.Деструктор срабатывает в тот момент, когда завершается работа программы и уничтожаются все данные.
Конструктор копирования по умолчанию. Такой конструктор представляется компилятором для каждого создаваемого класса и называется копирующим конструктором по умолчанию. Этот конструктор имеет единственный аргумент, являющийся объектом того же класса, что и конструктор: имя_класса(const Имя_класса &). Конструктор копирования создается всякий раз, когда создается новый объект и в качестве его значения выбирается существующий объект того же самого типа. Пусть у нас имеются инициализированный объект класса myClass obj1. Тогда, определив еще два объекта класса myClass, мы можем инициализировать их следующим образом: myClass obj2(obj1);myClass obj3 = obj1. В обоих случаях вызывается конструктор копирования по умолчанию, действия которого сводятся к копированию значений полей объекта obj