Слайд 1Лекция №4 по дисциплине
«Объектно-ориентированное программирование» на тему:
Статические объекты и функции.
Перегрузка
операций
Слайд 2Копирующий конструктор
Когда один объект присваивается другому, выполняется почленное копирование всех
его членов-данных. Присвоить объекту А объект В можно, если их
тип совпадает
Time t1(1, 3, 2011); //конструктор инициализации
Time t2=t1; // конструктор копирования
Компилятор автоматически создает копирующий конструктор, если он не определен программистом явно
Пример явного определения копирующего конструктора.
Time(const Time &t) {
day=t.day;
month=t.month;
year=t.year;
}
Слайд 3Вызов копирующего конструктора
Вызов копирующего конструктора происходит в следующих случаях:
в
операторе объявления Time t2=t1;
когда объект передается функции как параметр;
когда объект
возвращается в качестве значения функции
Пример 1.
Time t1(1, 3, 2011);
f(t1);
Пример 2.
f(Time(1, 3, 2011));
Слайд 4Массивы объектов
Объекты можно объединять в массивы:
Time t1[5];
Массивы можно инициализировать с
помощью списков инициализации.
Time t1[2]={Time(1,1,2011), Time(1,3,2011)};
Time t2[2]={Time(“01-Jan-2011”),
Time(“01-Mar-2011”)};
Time t3[2]={“ 01-Jan-2011”, “01-Mar-2011”};
В динамической памяти массивы объектов размещаются при помощи операции new:
Time *t= new Time[5];
При размещении в динамической памяти элементы массива объектов инициализируются только конструктором без параметров, поэтому он обязательно должен существовать
Слайд 5Статические переменные и функции
Статическая переменная является общей для всех
объектов данного класса
Объявление статического элемента начинается с ключевого слова
static
Статические элементы должны быть инициализированы только один раз
Статическая переменная может быть объявлена, но не может быть определена в объявлении класса
Слайд 6Пример объявления статической переменной
class A {
public:
static int S;
};
int A::S=0;
Обращение к открытой статической переменной:
объект_класса. имя_переменной
указатель_на_объект-> имя_переменной
имя_класса :: имя_переменной
К закрытым статическим переменным обращение должно происходить при помощи открытых членов-функций класса.
tPtr->getCount()
Time::getCount()
Слайд 7Указатель на себя
Каждый объект имеет указатель на себя, который
обозначается идентификатором this.
Он является скрытым параметром каждой член-функции
Тип указателя
this зависит от типа объекта.
В не-константной член-функции класса Time указатель this имеет тип
Time *const
Примеры:
this->day
(*this).day
Слайд 8Перегрузка операций
Чтобы разрешить операциям С++ работать с объектами класса,
их необходимо перегрузить
Операции перегружаются при помощи написания обычного определения
функции, но именем функции должно быть ключевое слово operator и символ перегружаемой операции.
Например, operator+ перегружает операцию сложения.
Слайд 9Перегрузка операций
Операция присваивания может использоваться с любым классом без перегрузки
Операция адреса & также может использоваться с объектами любого класса
без перегрузки
Часто перегрузить требуется не одну операцию, а целый перечень, например,
+, -, /, *.
Чаще всего перегружающей функцией делают член-функцию класса, или дружественную функцию.
Слайд 10Перегрузка операций
Большая часть операций С++ может быть перегружена:
+ - *
/ % & ! < > = += - =
*= /= << >> && ++ -- new delete
Не могут быть перегружены:
. :: ?: sizeof
Перегружать оператор-функцию можно многократно
Приоритет операций не может быть изменен посредством перегрузки
Слайд 11Пример перегрузки сложения для класса комплексных чисел
class Complex{
private:
float re, im;
public:
Complex
(float r, float i){
re=r; im=i;
}
Complex operator+(Complex);
};
Слайд 12Продолжение примера
Complex Complex::operator+(Complex c){ // перегружаем //сложение
Complex rez;
rez.re=re+c.re;
rez.im=im+c.im;
return rez;
}
int main()
{ // тестирующая функция
Complex c1= Complex (2, 5);
Complex c2=
Complex (5, 10);
Complex d;
d=c1+c2; // благодаря перегрузке такая операция //возможна
}
Слайд 13Пример перегрузки обычной функцией с двумя аргументами
Complex operator+ (Complex &first,
Complex &second) {
Complex rez;
rez.re=first.re+second.re;
rez.im= first.im+second.im;
return rez;
}
Нельзя изменить число
операндов, которое подразумевает операция
Нельзя создавать новые операции. Допускается перегрузка только существующих операций
Слайд 14Пример перегрузки операций передачи в поток и извлечения из потока
#include
#include
using std::setw;
class Phone { //опишем класс телеф.
номеров
friend ostream & operator<< (ostream&, const Phone&);
friend istream & operator>> (istream&, Phone&);
private:
char areaCode[4]; // 3 цифры кода области и null
char exchange[4]; // 3 цифры кода АТС и null
char line[5]; // 4 цифры линии и null
};
Слайд 15Продолжение примера
ostream & operator
Phone &num) {
input.ignore(); // пропустить (
input>> setw(4) >> num.areaCode; // ввести код //области
input.ignore(); // пропустить ( и пробел
input>> setw(4) >> num.exchange; // ввести код ATC
Слайд 16Окончание примера
input.ignore();
input>> setw(5) >> num.line;
return input;
}
int main()
{
Phone ph;
cout
cin>>ph;
cout<< “The phone number is” << ph<< endl;
return 0;
}
Слайд 17Каскадирование операций >> и >ph преобразуется компилятором в
вызов функции
operator>>(cin, ph);
Функция operator>> возвращает input
как ссылку на istream. Это разрешает каскадирование операций ввода объектов Phone. Например:
cin>>ph1 >> ph2;
Сначала будет выполнено cin>>ph1 посредством вызова функции operator>>(cin, ph1);
Этот вызов вернет cin как значение выражения cin>>ph1, оставшаяся часть выражения будет проинтерпретирована как cin>>ph2.
Слайд 18Перегрузка унарных операций
Унарная операция может быть перегружена:
как не-статическая член-функция
без аргументов
как обычная функция с одним аргументом
Пример. Перегрузка унарного
минуса.
Complex Complex::operator-()
{
return Complex (-re, -im);
}
Другой вариант этой же операции:
Complex& Complex::operator-() {
re=-re; im=-im;
return *this;
}
Слайд 19Перегрузка инкремента
Пример. Перегрузка префиксного инкремента.
Complex& Complex::operator++() {
++re; ++im;
return *this;
}
Если
компилятор встречает постинкремент с1++, он генерирует вызов функции
с1.operator++(0);
Прототип объявляется как
Complex
operator++(int);
Пример. Перегрузка постфиксного инкремента.
Complex Complex::operator++(int) {
return Complex(++re, ++im);
}
Слайд 20Перегрузка оператора присваивания
Операция присваивания по умолчанию определена для любого
класса и состоит в почленном копировании нестатических элементов класса.
Пример.
Complex& Complex::operator=(Complex
&c) {
re=c.re; im=c.im;
return *this;
}
Слайд 21Перегрузка оператора индекса массива
Пример.
class Day {
public:
char* operator[] (int n)
{
switch(n) {
case 1: return “Понедельник”;
case 2: return “Вторник”;
case 7: return
“Воскресенье”;
default: return “”;
}
}
};
Day d;
cout << d[2]; // выводит «Вторник»
Слайд 22Перегрузка преобразования типов
Операция преобразования применяется к объекту класса, преобразуя
его в объект другого класса или в объект встроенного типа.
Прототип функции
А:: operator char*();
объявляет перегруженную член-функцию приведения для создания объекта char* из объекта типа А. Если а – объект класса А, то, когда компилятор встречает выражение (char*)а, он генерирует вызов
а.operator char*();
Пример.
А:: operator int();
объявляет перегруженную член-функцию для преобразования объекта типа А в целый тип.