Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Ob.set(9);// Ошибка компиляции




ob.print();

ob.CBase::print();

return 0;

}

 

При компиляции выделенной строки вы получите сообщение:

Compiling...

error C2660: 'set': function does not take 1 parameters

Error executing cl.exe.

 

Замените ошибочную строку строкой b.set(9);

на ob.CBase::set(9); откомпилируйте и выполните программу, и вы увидите, что она выполняется без ошибки.

Результат выполнения посмотрите здесь inh1.exe

Другой способ решения этой проблемы–написать в производном классе небольшую встроенную функцию заглушку для вызова функции базового класса.

class CDerived:public CBase

{

protected:

int y;

public:

CDerived(int,int);

void print();

void set(int,int);

void bset(int i){CBase::set(i);} //Функция-заглушка

};

 

Выполнив

int main()

{

CDerived ob(5,6);

ob.set(7,8);

ob.print();

ob.bset(9); //

ob.print();

ob.CBase::print();

system("pause");

return 0;

}

 

Вызов ob.bset(9); дает тот же результат, что и ob.CBase::set(9);

 

Упражнение 2. В этом упражнении мы покажем использование виртуальных функций.

Создадим иерархию классов: «птицы» имеют свойство «летать» и наследуемый класс «пингвин», который летать не умеет.

#include<iostream.h>

//птицы

class bird{

//...

public:

void fly()const{cout<<"fly"<<endl;} //может летать

//Если не const, то при вызове в функции alarm() b.fly();

// сообщение

//cannot convert 'this' pointer from 'const class bird' to 'class bird &'

};

//пингвин

class penguin:public bird{

//...

public:

// Переопределяем, чтобы пингвин не летал

void fly()const{cout<<"nofly"<<endl;}

};

 

int main()

{

bird b;

penguin p;

b.fly();//летит

p.fly();//не летит

return 0;

}

 

Создадим и выполним эту программу. Все нормально: птицы летают, но пингвин не летает.

Усложним задание. Добавим функцию alarm() – сигнал «тревога», который поступает всем птицам, в том числе и пингвину. Реакция птиц на сигнал «тревога»: убежать, улететь.

 

#include<iostream.h>

//птицы

class bird{

//...

public:

void fly()const{cout<<"fly"<<endl; }

};

//пингвин

class penguin:public bird{

//...

public:

void fly()const{cout<<"nofly"<<endl;}

};

//Сигнал тревоги

void alarm(const bird& b)

{

b.fly();

}

 

int main()

{

bird b;

penguin p;

b.fly();//летит

p.fly();//не летит

alarm(b);//полетела

alarm(p);//как ни странно, и пингвин полетел

return 0;

}

Создадим и выполним эту программу. Видим, что все птицы, в том числе и пингвин, летят.

Сделаем функцию fly() виртуальной.

virtual void fly()const{cout<<"fly"<<endl;

Создадим и выполним эту программу. Все нормально: птицы летают, но пингвин не летает.

int main()

{

bird b;

penguin p;

b.fly();//летит

p.fly();//не летит

alarm(b);//полетела

alarm(p);//не летит, а только бежит

return 0;

}

Более грамотным решением будет создание абстрактного класса «птицы» с абстрактной виртуальной функцией fly(). В конкретном классе птиц эта функция переопределяется должным образом.

#include<iostream.h>

// Абстрактный класс-птицы

class bird{

//...

public:

virtual void fly()const=0;//Абстрактный метод-

//должен быть переопределен в производных классах

};

//ворона

class crow:public bird{

//...

public:

//Ворона летает

void fly()const{cout<<"fly"<<endl;}

};

 

//пингвин

class penguin:public bird{

//...

public:

//Пингвин не летает

void fly()const{cout<<"nofly"<<endl;}

};

//Сигнал тревоги

void alarm(const bird& b)

{

b.fly();

}

 

int main()

{

crow c;

penguin p;

c.fly(); // летит

p.fly(); //не летит

alarm(c); //полетела

alarm(p); //не летит, а бежит

return 0;

}

 

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

В языке С++ определены множества операций над переменными стандартных типов, такие как +, *, / и т.д. Каждую операцию можно применить к операндам определенного типа.

К сожалению, лишь ограниченное число типов непосредственно поддерживается любым языком программирования. Например, С и С++ не позволяют выполнять операции с комплексными числами, матрицами, строками, множествами. Однако все эти операции можно выполнить через классы в языке С++.

Рассмотрим пример.

Пусть заданы множества А и В:

А = {а1,а2,а3};

В = {a3,a4,a5},

и мы хотим выполнить операции объединения (+) и пересечения (*) множеств.

А+В = {a1,a2,a3,a4,a5}

А*В = {a3}.

Можно определить класс Set-“множество” и определить операции над объектами этого класса, выразив их с помощью знаков операций, которые уже есть в языке С++, например, + и *. В результате операции + и * можно будет использовать как и раньше, а также снабдить их дополнительными функциями (объединения и пересечения). Как определить, какую функцию должен выполнять оператор: старую или новую? Очень просто – по типу операндов. А как быть с приоритетом операций? Сохраняется определенный ранее приоритет операций. Для распространения действия операции на новые типы данных надо определить специальную функцию, называемую «операция-функция» (operator-function). Ее формат:

тип_возвр_значения operator знак_операции

(специф_параметров) {операторы_тела_функции}

При необходимости может добавляться и прототип:

тип_возвр_значения operator знак_операции

(специф_параметров)

Если принять, что конструкция operator знак_операции есть имя некоторой функции, то прототип и определение операции-функции подобны прототипу и определению обычной функции языка С++. Определенная таким образом операция называется перегруженной (overload).

Чтобы была обеспечена явная связь с классом, операция-функция должна быть либо компонентом класса, либо она должна быть определена в классе как дружественная и у нее должен быть хотя бы один параметр типа класс (или ссылка на класс). Вызов операции-функции осуществляется так же, как и любой другой функции С++: operatorÅ. Однако разрешается использовать сокращенную форму ее вызова: aÅ b, где Å –знак операции.

 

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

· Любая унарная операция Å может быть определена двумя способами: либо как компонентная функция без параметров, либо как глобальная (возможно дружественная) функция с одним параметром. В первом случае выражение Å Z означает вызов Z.operatorÅ(), во втором–вызов operatorÅ(Z).

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

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

Синтаксис:

а) в первом случае (описание в области класса):

тип_возвр_значения operator знак_операции

б) во втором случае (описание вне области класса):

тип_возвр_значения operator знак_операции(идентификатор_типа)

 

Примеры.

1)

class person

{int age;

//другие поля

public:

//конструкторы, деструктор и другие методы

void operator++(){ ++age;}

};

void main()

{

class person jon;

++jon;

}

 

2)

class person

{int age;

//другие поля

public:

//конструкторы, деструктор и другие методы

friend void operator++(person&);

};

 

void operator++(person&ob)

{++ob.age;}

 

void main()

{

class person jon;

++jon;

}

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...