Лабораторная работа №1

Программирование на языке С++ с использованием классов.

Цель работы: 1) изучить возможности программирования классов на языке С++; 2) получить основные навыки программирования манипуляторов ввода/вывода.

Теоретические сведения

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

Определение класса

Определение класса идентично определению структуры в С++, за исключением того, что

Пример 1. Определение класса.

class str {
    char *s;//элемент-данное
public://спецификатор открытого доступа
    str(char *word);//функция-элемент: конструктор
    ~str();//функция-элемент: деструктор
    void write();//функция-элемент: метод печати
};

Управление доступом

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

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

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

Метка-спецификатор private (закрытый) используется, если элементы-данные и функции-элементы должны быть доступны только для функций-элементов данного класса.

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

Элементы класса

Элементы класса делятся на две основные категории:

Данные-элементы

Данные-элементы классов С++ идентичны элементам структур языка С++ с некоторыми дополнениями:

Элементы-функции

Функция-элемент является функцией, объявленной (описанной) внутри определения класса. Тело функции может также определяться внутри определения класса, в этом случае функция называется встроенной (inline) функцией-элементом. Когда тело функции определяется вне тела класса, перед именем функции ставится префикс из имени класса и операции разрешения видимости (::).

Пример2.

class str {
    char *s;// указатель на строку
public:
    str(char *word) { // встроенный конструктор
        s=new char[strlen(word)+1];
        strcpy(s, word);
    };
    ~str() { // встроенный деструктор
        delete[] s;
    };
    void write();// объявление функции-элемента
};

void str::write() { // определение функции-элемента
    cout << s;
};

Доступ к данным-элементам

Функции-элементы находятся в области действия класса, в котором они определены. Т.о. они могут обращаться к любому элементу класса, используя просто имя переменной. Обычные функции или функции-элементы другого класса могут получить доступ к элементам-данным с помощью операции . или >, применяемых к представителю или указателю на представитель класса.

Пример 3.

class coord {
public:
    int x, y;// координаты x и y
};
int main() {
  coord org;// представитель класса координат
  coord *orgptr = &org;// указатель на представитель класса
  org.x = 0;// задание значения координаты x
  orgptr->y = 0;// задание значения координаты y
}

Вызов функций-элементов

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

Пример 4.

class coord {
    int x, y;// координаты x и y
public:
void setcoord(int _x, int _y)
// функция задания значений координат
{ x =_x; y =_y;
};
void getcoord(int &_x, int &_y)
//функция получения значений координат
{_x = x; _y = y;};
};
int main() {
  coord org;// представитель класса координат
  coord *orgptr = &org;// указатель на представитель класса
  org.setcoord(10, 10);// вызов функции-элемента
  // задания значений
  int col, row;
  orgptr->getcoord(col, row);// вызов функции-элемента
  // получения значений координат
}

Указатель this

Каждая нестатическая (не имеющая спецификатора static) функция-элемент имеет доступ к объекту, для которого вызвана, через ключевое слово this. Указатель this является указателем на тип_класса*.

Пример 5.

class simple {
public:
    simple();
    void greet() { cout<<" Hello!";};
};
simple::simple() {
    greet();// вызов
    this->greet(); // функции
    (*this).greet(); // greet()
}

Т.к. функции-элементы могут обращаться ко всем элементам класса просто по имени, в основном указатель this используется для возвращения указателя (return this) или ссылки (return *this) на подразумеваемый объект.

Конструктор

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

Для конструкторов выполняются следующие правила:

Деструктор

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

Пример 6.

file ctime.h

#ifndef __CTIME_H__
#define __CTIME_H__
class CTime
{char *timestr;
public:
CTime(char *str="00:00:00");//конструктор по умолчанию
CTime(const CTime& clk);//копирующий конструктор
~CTime();//деструктор
show();//функция-элемент
};//обязательно ставить точку с запятой, т.к. class –
// объявление типа
#endif

file ctime.cpp

#include <string.h>
#include <iostream.h>
#include "ctime.h"

CTime::CTime(char *str="00:00:00")
{
    timestr=new char[strlen(str)+1];
    strcpy(timestr,str);
}
CTime:: CTime(const time& clk)
{
    timestr=new char[strlen(clk.timestr)+1];
    strcpy(timestr,clk.timestr);
}
CTime::~ CTime()
{
    delete [] timestr;
}
CTime::show()
{
    std::cout << "Time is " << timestr << std::endl;
}

file main.cpp

#include "ctime.h"
int main(void) {
    CTime a;//для а вызывается конструктор по умолчанию
    CTime *b=new CTime;//для b вызывается конструктор по умолчанию
    CTime e(a);//для e вызывается копирующий конструктор
    //вызовем функцию-элемент
    a.show();//00:00:00
    b->show();//00:00:00
    e.show;//00:00:00
}

в конце области видимости автоматически вызываются деструкторы объектов в порядке, обратном вызову конструкторов, т.е. сначала для е, затем для d и т.д..

Форматируемый ввод/вывод. Манипуляторы.

При вводе/выводе данных можно воспользоваться манипуляторами, то есть специальными функциями форматирования, которые могут находиться в теле оператора ввода/вывода. Если в манипуляторе используются параметры, то необходимо подключение заголовочного файла <iomanip.h>.

Для сохранения и восстановления состояния потока используется функция-метод класса потока flags(). Например:

long a;

a=cout.flags();//для сохранения состояния потока в а

cout.flags(a);//для восстановления состояния потока из а

Манипулятор Назначение Ввод/вывод
dec Вывод числовых данных в десятичной системе счисления. Вывод
hex Вывод числовых данных в шестнадцатеричной системе счисления. Вывод
oct Вывод числовых данных в восьмеричной системе счисления. Вывод
endl Вывод символа новой строки и флэширование. Вывод
ends Вывод нуля (NULL). Вывод
flush Сброс буферизованового вывода на диск. Вывод
ws Пропуск начальных пробелов. Ввод
resetiosflags(long f) Сброс флагов, задаваемых в f. Ввод/вывод
setbase(int base) Устанавливает основание системы счисления для вывода данных. Вывод
setfill(char ch) Устанавливает символ заполнения ch. Вывод
setiosflags(long f) Установка флагов, задаваемых в f. Вывод
setprecision(int p) Задает число символов после десятичной точки, равным p. Вывод
setw(int w) Задает ширину поля, равной w позиций. Вывод

Примеры программирования

Пример 7. Вывод данных с использованием манипуляторов.

#include <iostream>
#include <iomanip>
#include <cmath>

int main() {
  double x, y;
  std::cout << "Input x ";
  std::cin >> x;
  y = sin(x);
  std::cout << std::setprecision(3);
  std::cout << std::setw(7) << x;
  std::cout << std::setw(7) << y;
  return 0;
}

Пример 8. Описать и определить класс-список.

Файл list.h содержит описание класса.

#pragma once

struct list {
    int inf;// информационное поле
    list *next;// указатель на следующий элемент списка
};

class CSpisok {
    list* head;// указатель на начало списка
public:
    CSpisok (int);
    CSpisok (CSpisok&);
    ~CSpisok();
    void print ();
};

Файл list.cpp содержит определение функций-элементов.

#include <cstdlib>
#include <iostream>
#include <iomanip>
#include "list.h"
//конструктор инициализирует список из n элементов по принципу "очередь"
CSpisok:: CSpisok(int n) {
    head = NULL;
    list *p,*pn;
    for (int i = 0; i < n; i++) {
        p = new list;
        p->inf = random(100)-50;
        p->next = NULL;
        if (head == NULL) head = p;
        else pn->next = p;
        pn = p;
    }
}
//конструктор копии класса CSpisok
CSpisok:: CSpisok (const CSpisok& s) {
    head = NULL;
    list *sp = s.head, *p, *pn;
    while (sp) {
        p = new list;
        p->inf = sp->inf;
        p->next = NULL;
        if (head == NULL) head = p;
        else pn->next = p;
        pn = p;
        sp = sp->next;
    }
}
//деструктор - уничтожает объект класса список из памяти
CSpisok::~CSpisok() {
    list *p;
    while (head) {
        p = head;
        head = head->next;
        delete p;
    }
}
//функция-элемент печати содержимого списка
void CSpisok::print()
{
    list *p = head;
    while (p) {
        std::cout << std::setw(5) << p->inf;
        p = p->next;
    }
    std::cout << std::endl;
}

Файл main.cpp содержит основную функцию.

#include <iostream>
#include <iomanip>
#include "list.h"
int main() {
    spisok s1(10), // создание списка из 10 элементов
    s2(s1), // s2- копия списка s1
    s3(15); // создание списка из 15 элементов
    s1.print(); // печать s1
    s2.print(); // печать s2
    s3.print(); // печать s3
}

В проект включены файлы: main.cpp и list.cpp.

Результаты выполнения программы:

-49  -50 -17 -47 -15 -29  3 -31 20 44
-49  -50 -17 -47 -15 -29  3 -31 20 44
-23  -6 -40 19  6 -46 -34 31 18 26 32 45 -29 -8 45

Контрольные вопросы

  1. Что представляет собой класс?
  2. Какие спецификации доступа используются при описании класса?
  3. Что является элементами класса?
  4. Как осуществляется доступ к элементам класса?
  5. Для чего используется указатель this?
  6. Что такое конструктор?
  7. Что такое деструктор?

Варианты заданий

  1. Определить класс-строку. В класс включить два конструктора: для определения класса строки строкой символов и путем копирования другой строки (объекта класса строки). Предусмотреть функции поиска слова в строке и добавления другой строки, начиная с позиции N
  2. Определить класс-строку. В класс включить два конструктора: для определения класса строки строкой символов и путем копирования другой строки (объекта класса строки). Предусмотреть функции слияния двух строк и функцию подсчёта предложений в строке.
  3. Определить класс-строку. В класс включить два конструктора: для определения класса строки строкой символов и путем копирования другой строки (объекта класса строки). Предусмотреть функции сортировки слов в строке по-алфавиту и подсчёта количества слов.
  4. Определить класс список элементов. В определение класса включить два конструктора: для определения списка по его размеру и путем копирования другого списка. Предусмотреть функции подсчёта количества элементов списка и добавления одного списка в другой список, начиная с позиции N.
  5. Определить класс список элементов. В определение класса включить два конструктора для определения списка по его размеру и путем копирования другого списка. Предусмотреть функции сортировки списка по возрастанию и вывода на экран в обратном порядке.
  6. Определить класс список элементов. В определение класса включить два конструктора для определения списка по его размеру и путем копирования другого списка. Предусмотреть функции инверсии списка (123->321) и поиска подсписка в списке.
  7. Определить класс сортированный список элементов. В определение класса включить два конструктора для определения списка по его размеру и путем копирования другого списка. Предусмотреть функции добавления элемента и слияния двух сортированных списков.
  8. Определить класс список элементов. В определение класса включить два конструктора для определения списка по его размеру и путем копирования другого списка. Предусмотреть функции формирования нового списка из элементов, входящих только в один из двух других списков и вычисления суммы элементов списков.
  9. Определить класс квадратная матрицу. В класс включить два конструктора для определения матрицы по количеству элементов и путем копирования другой матрицы. Предусмотреть функции вычисления детерминанта матрицы и умножения матрицы на число.
  10. Определить класс стек. В класс включить два конструктора для определения стека по его размеру и путем копирования другого стека. Предусмотреть функции вычисления среднего арифметического из элементов стека и нахождения элемента по его номеру
  11. Определить класс вектор. В класс включить два конструктора для определения вектора по его размеру и путем копирования другого вектора. При задании вектора по его размеру предусмотреть его заполнение случайными числами. Предусмотреть функции умножения векторов и подсчёта суммы элементов вектора.
  12. Определить класс вектор. В класс включить два конструктора для определения вектора по его размеру и путем копирования другого вектора. При задании вектора по его размеру предусмотреть его заполнение случайными числами. Предусмотреть функции нахождения максимального и минимального из элементов вектора и умножения вектора на число.
  13. Определить класс вектор. В класс включить два конструктора для определения вектора по его размеру и путем копирования другого вектора. При задании вектора по его размеру предусмотреть его заполнение случайными числами. Предусмотреть функции сортировки вектора по возрастанию и нахождения среднего арифметического из элементов вектора.
  14. Определить класс прямоугольная матрицу. В класс включить два конструктора для определения матрицы по количеству элементов и путем копирования другой матрицы. Предусмотреть функции вычисления произведения матрицы на матрицу и сложения матриц.
  15. Определить класс «вектор координат в пространстве». В класс включить два конструктора для определения вектора по умолчанию и путем копирования другого вектора. При задании вектора по умолчанию предусмотреть его заполнение случайными числами. Предусмотреть функции нахождения длины вектора, умножения вектора на вектор, скалярного произведения векторов.