Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Листинг 10.7



#include <iostream.h>

class Test

{

public:

Test (int = 0);

void print() const;

private:

int x;

};

Test::Test(int a) {x = a;}//конструктор

void Test::print() const

{

cout <<”x = “<< x << endl <<”this->x = “ << this -> x<<endl <<”(*this).x=”<<(*this).x<<endl;

}

main()

{

Test a(12);

a.print();

return 0;

}

Перегрузка операций. Любая операция, определенная в C++, может быть перегружена для создан­ного класса. Это делается с помощью функций специального вида, называемых функциями-операциями (операторными функциями). Общий вид такой функции:

возвращаемый_тип operator # (список параметров)

{

тело функции

}

где вместо знака # ставится знак перегруаемой операции.

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

Например, два варианта перегрузки операции сложения для класса Point: первый вариант - в форме метода класса:

class Point

{

double x. у: public:

//...

Point operator +(Point&);

};

Point Point::operator +(Point& p)

{

return Point(x + p.x, у + р.у);

}

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

class Point

{

double x, у;

public:

//...

friend Point operator +(Point&. Point&);

};

Point operator +(Point& p1. Points p2)

{

return Point(p1.x + p2.x. p1.у + p2.y);

}

Независимо от формы реализации операции «+» можно теперь написать:

Point pl(0, 2), р2(-1, 5);

Point рЗ = p1 + р2;

Встретив выражение pi + р2, компилятор в случае первой формы перегрузки вызовет метод p1.operator + (p2), а в случае второй формы перегрузки - глобальную функцию operator + (p1, р2).

Результатом выполнения данных операторов будет точка рЗ с координатами х = -1, у = 7.

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

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

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

Point& operator ++(); // префиксный инкремент

Point operator ++(int); // постфиксный инкремент

Реализация данных операций на примере класса Point:

Point& Point::operator ++()

{

x++;

y++;

return *this;

}

Point Point::operator ++(int)

{

Point old = *this;

X++;

y++;

return old;

}

В префиксной операции осуществляется возврат резуль­тата по ссылке. Это предотвращает вызов конструктора копирования для созда­ния возвращаемого значения и последующего вызова деструктора. В постфикс­ной операции инкремента возврат по ссылке не подходит, поскольку необходимо вернуть первоначальное состояние объекта, сохраненное в локальной переменной old. Таким образом, префиксный инкремент является более эффективной операцией, чем постфиксный инкремент.

Использование префиксного инкремента (декремента) для параметра цикла for дает бо­лее эффективный программный код.

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

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

Например, для класса Man перегрузку операции присваивания мож­но определить следующим образом:

// Man.h (интерфейс класса) class Man

{

public:

//...

Man& operator =(const Man&): //операция присваивания private:

char* pName;

II...

};

// Маn.срр (реализация класса) //...

Man& Man::operator =(const Man& man)

{

if (this == &man) return *this; // проверка на самоприсваивание

delete [] pName; //уничтожить предыдущее значение

pName = new char[strlen(man.pName) + 1];

strcpy(pName. man.pName);

birth_year = man.birth_year;

pay = man.pay;

return *this;

}

Моменты реализации операции присваивания:

- убедитесь, что не выполняется присваивание вида х = х. Если левая и правая части ссылаются на один и тот же объект, то делать ничего не надо. Если не перехватить этот особый случай, то следующий шаг уничтожит значение, на
которое указывает pName, еще до того, как оно будет скопировано;

- удалите предыдущие значения полей в динамически выделенной памяти;

- выделите память под новые значения полей;

- скопируйте в нее новые значения всех полей;

- возвратите значение объекта, на которое указывает this (то есть *this).

Статические элементы класса. До сих пор одноименные поля разных объектов одного и того же класса были уникальными. Но что делать, если необходимо создать переменную, значение которой будет общим для всех объектов конкретного класса? Если воспользо­ваться глобальной переменной, то это нарушит принцип инкапсуляции данных. Модификатор static как раз и позволяет объявить поле в классе, которое будет общим для всех экземпляров класса. Кроме объявления статического поля в классе, необходимо также дать его определение в глобальной области ви­димости программы, например:

class Coo

{

static int count: // объявление в классе // остальной код

};

int Coo::count = 1; // определение и инициализация

// int Coo::count; // по умолчанию инициализируется нулем

Аналогично статическим полям могут быть объявлены и статические методы класса (с модификатором static). Они могут обращаться непосредственно толь­ко к статическим полям и вызывать только другие статические методы класса, потому что им не передается скрытый указатель this. Статические методы не могут быть константными (const) и виртуальными (virtual). Обращение к статическим методам производится так же, как к статическим полям - либо через имя класса, либо, если хотя бы один объект класса уже создан, через имя объекта.





Дата публикования: 2015-10-09; Прочитано: 282 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2025 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.241 с)...