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 Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|