Перегрузка унарных операций

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

class monstr {

monstr & operator ++( ) {++health; return *this;}

};

monstr Vasia;

cout << (++Vasia).get_health ( );

Если функция определяется вне класса, она должна иметь один параметр типа класса:

class monstr {

friend monstr & operator ++ (monstr &M);

};

monstr &operator ++(monstr &M) {++M.health; return M;}

Если не описывать функцию внутри класса как дружественную, нужно учитывать доступность изменяемых полей. В данном случае поле health недоступно вызовам извне, так как описано со спецификатором private, поэтому для его изменения требуется использование соответствующего метода. Введем в описание класса monstr метод change_health, позволяющий изменить значение поля health:

void change_health (in the) {health=he;}

Тогда можно перегрузить операцию инкремента с помощью обычной фун кции, описанной вне класса:

monstr &operator ++ (monstr &M) {

int h=M.get_health ( ); h++;

M.change_health (h);

return M;

}

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

class monstr {

monstr operator ++ (int) {

monstr M(*this); health ++;

return M;

}

};

monstr Vasia;

cout <<(Vasia++).get_health ( );

 

Перегрузка бинарных операций

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

class monstr {

bool operator > (const monstr &M) {

if (health >M.get_health ( ) ) return true;

return false;

}

};

Если функция определяется вне класса, она должна иметь два параметра типа класса:

bool operator > (const monstr &M1, const monstr &M2) {

if (M1.get_health ( ) > M2.get_health ( )) return true;

return false;

}

 

Перегрузка операции присваивания

Операция присваивания определена в любом классе по умолчанию как поэлементное копирование. Эта операция вызывается каждый раз, когда одному существующему объекту присваивается значение другого. Если класс содержит поля, память под которые выделяется динамически, необходимо определить собственную операцию присваивания. Для того чтобы сохранить смысл присваивания, функция-операция должна возвращать ссылку на объект, для которого она вызвана, и принимать в качестве параметра единственный аргумент – ссылку на присваиваемый объект.

class monstr &operator = (const monstr &M) {

//

if (&M= =this) return *this;

if (name) delete [ ] name; //

if (M.name) {

name = new char [strlen(M.name) c+1];

strcpy (name, M.name;}

else name =0;

health = M.health; ammo = M.ammo;

skin = M.skin;

return *this;

}

Возврат из функции указателя на объект делает возможной цепочку операций присваивания:

monstr A(10), B, C;

C = B = A;

Операцию присваивания можно определять только как метод класса. Она не наследуется.

 

Перегрузка операции приведения типа

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

оperator имя_нового_типа ( );

Пример

monstr : : operator int ( ) {return health;}

 

Наследование

 

Ключи доступа

При описании класса в его заголовке перечисляются все классы, являющиеся для него базовыми. Возможность обращения к элементам этих классов регулируется с помощью ключей доступа private, protected и public:

class имя : [private | protected | public] базовый класс

{тело класса};

Если базовых классов несколько, они перечисляются через запятую. Ключ доступа может стоять перед каждым классом, напрмер:

class A {…};

class B {…};

class C {…};

class D: A, protected B, public C {…};

По умолчанию для классов используется ключ доступа private, а для структуры – public (см. таблицу).

 

Связь ключей доступа и спецификаторов доступа

 

Ключ доступа Спецификатор в производном классе Доступ в производном класее Комментарий
private private protected public private private private Все элементы private
protected private protected public private protected protected Все элементы protected, кроме private

 

Окончание таблицы

public private protected public private protected public Не изменяется

 

Из таблицы видно, что private элементы базового класса недоступны вне зависимости от ключа. Обращение к ним может осуществляться только через методы базового класса.

Простое наследование

Простым называется наследование, при котором производный класс имеет одного родителя. Для различных методов класса существуют разные правила наследования – например, конструкторы и операция присваивания в производном классе не наследуются, а деструкторы наследуются.

Пример.Описание класса daemon, производного от класса monstr:

enum color {red, green, blue};

// monstr

class monstr {

//

int health, ammo;

color skin;

char * name;

public:

//

monstr (int he=100, int am=10);

monstr (color sk);

monstr (char *nam);

monstr (monstr &M);

//

~ monstr ( ) {delete [ ] name;}

//

monstr & operator + + ( ) {

+ + health; return *this;

}

monstr operator + + (int) {

monstr M (*this);

health + +; return M;

}

operator int ( )

return health;

}

bool operator > (monstr &M) {

if (health > M.get_heath ( )) return true;

return false;

}

const monstr & operator = (monsr &M) {

if (&M = = this) return *this;

if (name) delete [ ] name;

if (M.name) {

namt = new char [strlen(M.name)+1];

strcpy (name, M.name); }

else name = 0;

health =M.health; ammj=M.ammo; skin =M.skin;

return *this;

}

//

int get_health ( ) const {return health;}

int get_ammo ( ) const { return ammo;}

//

void change_health (int he) {healt=he;}

//

void draw (int x, int y, int scale, int position);

//

monstr: : monstr (int he, int am):

health (he), ammo (am), skin (red), name (0) { }

monstr : : monstr (monstr &M) {

if (M.name) {

name = new char [strlen(M.name)+1];

strcpy (name, M.name;}

else name = 0;

health =M.health; ammo=M.ammo; skin = M.skin;

}

monstr : :monstr (color sk) {

switch (sk) {

case red: health =100; ammo=1`0; skin = red;

name=0; break;

case green: health =100; ammo=20, skin=green;

name=0; break;

case blue: health=100; ammo=40; skin=blue;

name=0; break;

}

}

monstr : : monstr (char * nam) {

name= new char [strlen(nam)+1];

strcpy(name, nam);

health=100; ammo=10; skin=red;

}

void monstr: : draw (int x, int y, int scale, int position)

{/**/}

//

class daemon : public monstr {

int brain;

public:

//

daemon (int br=10) {brain=br;}

daemon (color sk): monstr (sk) {brain =10;}

daemon (char *nam) : monstr (nam) {brain=10;}

daemon (daemon &M): monstr (M) {brain=M.brain;}

//

const daemon &operator = (daemon &M) {

if (&M = =this) return *this;

brain = M.brain;

monstr : : operator =(M);

return *this;

}

//

void think ( );

//

void draw (int x, int y, int scale, int position);

}

//

void daemon : : think ( ) {/* */}

void daemon : : draw (int x, int y, int scale, int position) {/* */}

 

!!! В классе daemon введено поле brain и метод think, определены собственные конструкторы и операция присваивания, а также переопределен метод draw. Все поля класса monstr, операции (кроме присваивания) и методы get_health, get_ammo и change_health наследуются в классе daemon, а деструктор формируется по умолчанию.