Download - C++ Базовый. Занятие 09
Модуль 3: Основные понятия объектно-ориентированного программирования.
Темы лекции: Продолжение введения в ООП.Перегрузка операций.
Практическое задание: Перегрузка операций.
Тренер: Игорь Шкулипа, к.т.н.
C++ Базовый. Занятие 9
http://www.slideshare.net/IgorShkulipa 2
Продолжение введения в ООП
http://www.slideshare.net/IgorShkulipa 3
Дружественные функции
Дружественные функции – это функции, объявленные вне класса,но имеющие доступ к закрытым и защищенным полям данного класса
Дружественная функция объявляется внутри класса с модификаторомfriend
Дружественные функции не являются членами класса, поэтому им непередается указатель this
Дружественные операции, как и дружественные функции, могутиметь доступ к приватным и защищенным методам класса
class Class1
{
friend void FriendMethod();
};
http://www.slideshare.net/IgorShkulipa 4
Дружественные классы
Некоторым классам может понадобиться доступ к закрытым данным другдруга.
В этом случае необходимо объявить дружественный класс внутриопределения класса
class Class1;
class Class2
{
friend class Class1;
private:
int data;
};
Дружественная связь между классами является самой сильной.
Реализации классов оказываются связанными, что противоречитпринципу инкапсуляции.
(!) Не используйте дружественные классы до тех пор, пока ихиспользование не окажется единственным способом решения задачи
http://www.slideshare.net/IgorShkulipa 5
Статические данные и методы
Для каждого объекта создается своя собственная копия членов данных.
Для некоторых классов было бы удобно использовать данные, общиедля всех экземпляров данного класса (например, строковоепредставление имени класса или константы, общие для всехэкземпляров класса, область видимости которых должна бытьограничена методами класса)
Такие поля и методы называют статическими и объявляют при помощиключевого слова static
class Class1
{
static void StaticMethod();
};
http://www.slideshare.net/IgorShkulipa 6
Особенности статических методов
◦ Статические методы не получают указатель this.
◦ Статические методы могут обращаться только к статическим даннымкласса.
◦ Статические методы могут вызывать только статические методы(либо нестатические, если им передается указатель или ссылка наобъект класса).
◦ Статические методы имеют доступ к закрытым и защищенным полями методам класса, через экземпляры классов.
◦ Доступ к статическим методам и данным класса осуществляется поимени класса (создавать экземпляр не требуется).
http://www.slideshare.net/IgorShkulipa 7
Применение статических методов
◦ Паттерн «одиночка» (singleton).
◦ Объект с глобальным доступом, существующий в программе вединственном экземпляре.
◦ Методы и данные, характерные для класса в целом, а не дляотдельных его экземпляров.
◦ Создание классов-утилит
http://www.slideshare.net/IgorShkulipa 8
Вложенное объявление классов
Язык C++ позволяет разместить объявление одного класса (или другоготипа данных) внутри объявления другого.
Это полезно, когда вложенный тип данных используется только внешнимклассом, или совместно с ним.
Использование вложенного класса может происходить двумя способами:
⚫ Из методов внешнего класса – по имени вложенного класса
⚫ Снаружи – при помощи указания имени внешнего класса:ExternalClass::InternalClass
http://www.slideshare.net/IgorShkulipa 9
Пример вложенного объявления классов
class ExternalClass
{
public:
class InternalClass
{
public: void InternalMethod();
};
private:
void ExternalMethod()
{
InternalClass inClass;
inClass.InternalMethod();
}
};
void main()
{
ExternalClass::InternalClass inClass;
inClass.InternalMethod();
}
http://www.slideshare.net/IgorShkulipa 10
Шаблоны проектирования (паттерны)
Шаблон проектирования – это архитектурная конструкция,представляющая собой решение проблемы проектирования врамках некоторого часто возникающего контекста.
http://www.slideshare.net/IgorShkulipa 11
Шаблон «Одиночка» (Singleton)
#include <iostream>
using namespace std;
class Singleton
{
public:
static Singleton* GetInstance()
{
if (_instance==NULL) _instance= new Singleton();
return _instance;
}
void Method1(){cout<<"Method1\n";}
void Method2(){cout<<"Method2\n";}
private:
Singleton(){}
static Singleton* _instance;
};
Singleton::_instance=NULL;
int main()
{
Singleton* singleton = Singleton::GetInstance();
singleton->Method1();
singleton->Method2();
}
http://www.slideshare.net/IgorShkulipa 12
Применение Singleton
Применяется, когда нужен только один экземпляр класса.Например для хранения глобальной конфигурации системы,для ведения логов, связи с базой данных и т.д.
Основное преимущество перед глобальными переменными втом, что экземпляр класса создается не при инициализациипрограммы, а по первому требованию.
http://www.slideshare.net/IgorShkulipa 13
Перегрузка операций
http://www.slideshare.net/IgorShkulipa 14
Для чего нужна перегрузка операций
Для некоторых типов данных естественными может оказатьсяиспользование операций над базовыми типами:
⚫+= и + для конкатенации строк
⚫ -- и ++ для итераторов
⚫ арифметические операции для векторов и комплексныхчисел
⚫ [] для векторов и матриц
⚫= для классов с собственным конструктором копирования
⚫ операции сравнения для строк и других типов
http://www.slideshare.net/IgorShkulipa 15
Перегрузка операций
Для пользовательских типов данных C++ позволяет задатьсобственные операции
⚫Некоторые из них всегда определяются внутри класса
⚫=, +=, -=, *= и т.д.
⚫Некоторые – снаружи (операции, в которых применяютсябазовые типы).
⚫Некоторые – где угодно.
Синтаксис:
<тип> operator <О>(параметры)
http://www.slideshare.net/IgorShkulipa 16
Ограничения
◦ Приоритет операций над пользовательскими типами тот же,что и для базовых типов
◦ Нельзя переопределить операции точка (.) и sizeof
◦ Бинарные операции остаются бинарными, унарные -унарными
http://www.slideshare.net/IgorShkulipa 17
Пример
class Complex
{
private:
double _im;
double _re;
public:
Complex();
Complex(double );
Complex(double, double);
~Complex();
}
Задача: выполнить перегрузку операций для нового типаданных.
http://www.slideshare.net/IgorShkulipa 18
Класс «Комплексное число»class Complex
{
private:
double _im;
double _re;
public:
Complex();
Complex(double );
Complex(double, double);
Complex (Complex &c);
~Complex();
Complex operator = (Complex &c)
{ this->SetIm(c.GetIm()); this->SetRe(c.GetRe()); return (*this); }
friend bool operator ==(const Complex& left, const Complex& right);
friend Complex operator +(const Complex& left, const Complex& right);
friend Complex operator -(const Complex& left, const Complex& right);
friend Complex operator *(const Complex& left, const Complex& right);
double GetRe(){return _re;}
double GetIm(){return _im;}
void SetRe(double re){_re=re;}
void SetIm(double im){_im=im;}
}
http://www.slideshare.net/IgorShkulipa 19
Конструкторы и деструктор
Complex::Complex()
:_re(0), _im(0)
{
}
Complex::Complex(double re)
:_re(re), _im(0)
{
}
Complex::Complex(double re, double im)
{
_re=re; _im=im;
}
Complex::Complex (Complex &c)
{
_re=c.GetRe(); _im=c.GetIm();
}
Complex::~Complex()
{
}
http://www.slideshare.net/IgorShkulipa 20
Операция сравнения
bool operator ==(const Complex& left, const Complex& right)
{
if ((left.GetRe()==right.GetRe()) &&
(left.GetIm()==right.GetIm()))
{
return true;
}
else
{
return false;
}
}
http://www.slideshare.net/IgorShkulipa 21
Арифметические операции
Complex operator +(const Complex& left, const Complex& right)
{
Complex temp;
temp.SetRe(left.GetRe() + right.GetRe());
temp.SetIm(left.GetIm() + right.GetIm());
return temp;
}
Complex operator -(const Complex& left, const Complex& right)
{
Complex temp;
temp.SetRe(left.GetRe() - right.GetRe());
temp.SetIm(left.GetIm() - right.GetIm());
return temp;
}
Complex operator *(const Complex& left, const Complex& right)
{
Complex temp;
double re=left.GetRe()*right.GetRe() – left.GetIm()*right.GetIm();
double im=left.GetRe()*right.GetRe() + left.GetIm()*right.GetIm();
temp.SetRe(re);
temp.SetIm(im);
return temp;
}
http://www.slideshare.net/IgorShkulipa 22
Потоки ввода-вывода
cin и cout - объекты классов istream (от Input Stream - потокввода) и ostream (от Output Stream - поток вывода)
соответственно. Именно для этих классов перегруженыоператоры извлечения и вставки (<< и >>).
Базовым классом является класс ios (от Input/Output Stream -потоковый ввод/вывод). У класса ios довольно много
производных классов.
Наследниками istream и ostream являются ifstream (от InputFile Stream) и ofstream (от Output File Stream). Которые
используются для ввода/вывода в файлы.
Кроме того, есть ещё один класс - fstream (от File Stream -фаловый поток), в котором объединены возможности ifstream
и ofstream. fstream наследуется одновременно и от istream,и от ostream.
http://www.slideshare.net/IgorShkulipa 23
Перегрузка операторов ввода-выводаclass Complex
{
... // Расширение класса Complex
friend ostream operator <<(ostream& out, Complex& c);
friend istream operator >>(istream& in, Complex& c);
}
ostream &operator<<(ostream &out, Complex &c)
{
if (c.GetIm()==0) out<<c.GetRe()<<“\n”;
if (c.GetIm()>0) out<<c.GetRe()<<“+”<<c.GetIm()<<“i”<<“\n”;
if (c.GetIm()<0) out<<c.GetRe()<<“-”<<-c.GetIm()<<“i”<<“\n”;
return out;
}
istream &operator>>(istream &in, Complex &c)
{
double re, im;
in >> re >> im;
c.SetRe(re); c.SetIm(im);
return in;
}
http://www.slideshare.net/IgorShkulipa 24
Результат
#include “complex.h”
void main()
{
Complex c1(1,2);
Complex c2(2,3);
cout << c1;
cout << c2;
cin >> c1;
cin >> c2;
cout << c1+c2;
cout << c1-c2;
cout << c1*c2;
}
http://www.slideshare.net/IgorShkulipa 25
Лабораторная работа №9. Перегрузка операций
Создать класс «Вектор» произвольного размера.
Реализовать методы:
⚫ Конструкторы и деструктор
⚫ Доступа к данным
⚫ Вычисления модуля вектора
Выполнить перегрузку операций:
⚫ Сложения, вычитания, скалярного умножения векторов
⚫ Умножения вектора на скаляр
⚫ Сравнения векторов (==, !=)
⚫ Операции присваивания (=)
⚫ Операцию индексации ( [ ] )
⚫ Операции ввода-вывода
Создать приложение для демонстрации работы класса.
Меню приложения реализовать в виде класса, согласно паттернуSingleton.
http://www.slideshare.net/IgorShkulipa 26
Бонусный слайд №1. Заголовок класса «Вектор»class Vector {
private:
double* _data; int _size;
public:
Vector();
Vector(int);
Vector(double*, int);
Vector(Vector&);
~Vector();
Vector operator = (Vector &v) {//Код оператора}
friend bool operator ==(const Vector& left, const Vector& right);
friend bool operator !=(const Vector& left, const Vector& right);
friend Vector operator +(const Vector& left, const Vector& right);
friend Vector operator -(const Vector& left, const Vector& right);
friend double operator *(const Vector& left, const Vector& right);
friend Vector operator *(const Vector& vect, double scalar);
friend ostream operator <<(ostream& out, Vector& v);
friend istream operator >>(istream& in, Vector& v);
double operator[](int i);
int GetSize();
double* GetData();
void SetSize(int);
void SetData(double*);
}
http://www.slideshare.net/IgorShkulipa 27
Бонусный слайд №2. Операция индексации
double Vector::operator[](int i)
{
if(i<_size)
{
return _data[i];
}
else
{
return NULL;
}
}