|
|||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Перегрузка функций (методов класса). Почему следует использовать перегрузку. Перегрузка функций, перегрузка конструкторовМетоды классов, так же как и обычные функции C++, можно перегружать. Перегрузка функций означает, что в текущей области действия одно и то же имя могут использовать несколько функций. Компилятор выбирает нужную функцию, учитывая количество и тип аргументов, использованных при ее вызове. Перегруженная функция выполняет различные действия, зависящие от типов данных, передаваемых ей в качестве аргументов. Функция starline() выводит на экран линию из 45 символов *, а функция repchar() выводит заданный символ заданное число раз, используя два аргумента. charline() всегда печатает 45 символов, но позволяет задавать печатаемый символ. Все три функции, starline(), repchar() и charline(), выполняют схожие действия, но их имена различны. Для программиста это означает, что нужно запомнить эти имена и различия между действиями функций. Очевидно, что было бы гораздо удобнее использовать одно и то же имя для всех трех функций, несмотря на то, что они используют различные наборы аргументов. #include <iostream> using namespace std; void repchar(); // прототипы void repchar(char); void repchar(char, int); int main() { repchar(); repchar('='); repchar('+', 30); return 0; } //---функция repchar()----------------------------- // выводит на экран 45 символов '*' void repchar() { for(int j=0; j<45; j++) // цикл, выполняющийся 45 раз cout << '*'; // вывод символа '*' cout << endl; } //--- функция repchar()----------------------------- // выводит 45 заданных символов void repchar(char ch) { for(int j=0; j<45; j++) // цикл, выполняющийся 45 раз cout << ch; // вывод заданного символа cout << endl; } Первые две из линий имеют длину 45 символов, третья — 30 символов. В программе содержатся три функции с одинаковым именем. Каждой из функций соответствует свое объявление, определение и вызов. Каким же образом компилятор различает между собой эти три функции? Здесь на помощь приходит сигнатура функции, которая позволяет различать между собой функции по количеству аргументов и их типам. Другими словами, объявление void repchar(); не содержащее аргументов, и объявление void repchar(char, int); задают разные функции. // функция repchar() выводит заданный символ заданное число раз void repchar(char ch, int n) { for(int j=0;j<n; j ++) // цикл, выполняющийся n раз cout << ch; // вывод заданного символа cout << endl; } Эта программа выводит на экран три различных вида линий: ********************************************* ================================= ++++++++++++++++++++++++++++++ Различные типы аргументов Аналогичным образом можно определить несколько функций с одинаковыми именами и одинаковым количеством аргументов, но различными типами этих аргументов. Следующая программа использует перегруженную функцию для вывода расстояния в виде числа футов и числа дюймов. Аргументом функции может являться как структурная переменная типа Distance, так и обычная переменная типа float. В зависимости от типа аргумента, указанного при вызове, будет исполняться одна из двух функций. #include <iostream> using namespace std; struct Distance { int feet; float inches; }; void engldisp(Distance); // прототипы void engldisp(float); int main() { Distance d1; // длина типа Distance float d2; // длина типа float // ввод значения d1 cout << "\nВведите число футов: "; cin >> d1.feet; cout << "Введите число дюймов: "; cin >> d1.inches; // ввод значения d2 cout << "Введите длину в дюймах: "; cin >> d2; cout << "\nd1 = "; engldisp(d1); // вывод значения d1 cout << "\nd2 = "; engldisp(d2); // вывод значения d2 cout << endl; return 0; } //-------- функция engldisp()---------------- void engldisp(Distance dd) // параметр dd типа Distance { cout <<dd.feet <<"\'-" << dd.inches <<"\""; } //-------------------------------------------------------- //engldisp() // вывод переменной типа float в футах и дюймах void engldisp(float dd) // параметр dd типа float { int feet =static_cast<int>(dd /12); float inches = dd - feet*12; cout <<feet <<"\'-" << inches <<"\""; } Пользователю предлагается ввести два расстояния: первое — в виде отдельно вводимых количества футов и количества дюймов, а второе — в виде количества дюймов (например, 109,5 дюймов вместо 9'-1,5"). Программа вызывает перегруженную функцию engldisp() для того, чтобы вывести первое значение, имеющее тип Distance(), и второе значение, имеющее тип float. Обратите внимание на то, что, несмотря на одинаковый результат работы различных версий функции engldisp(), код самих функций различен. Той из функций, которая использует в качестве аргумента расстояние в дюймах, необходимо выполнить преобразование вещественного значения к типу int перед тем, как вывести результат на экран. Использование перегруженных функций упрощает процесс разработки программы, так как у программиста нет необходимости запоминать множество имен функций. Перегруженные конструкторы Было бы удобно производить инициализацию переменных класса Distance в момент их создания, то есть использовать объявления типа Distance width(5, 6.25); где определяется объект width, сразу же инициализируемый значениями 5 и 6.25 для футов и дюймов соответственно. Чтобы сделать это, вызовем конструктор следующим образом: Distance(int ft, float in): feet(ft), inches(in) { } Мы инициализируем поля feet и inches теми значениями, которые передаются конструктору в качестве аргументов. Тем не менее, мы хотим сохранить возможность определять переменные класса Distance без инициализации, подобно тому, как мы делали в программе. В программе ENGLOBJ не было конструктора, но определения работали без ошибок. Это связано с наличием конструктора без параметров, называемого конструктором по умолчанию. Если же для нас важно, какими значениями будут инициализироваться поля объекта класса, то нам следует явно определить конструктор. Distance(): feet(O), inches(O.O) //конструктор по умолчанию { } //тело функции пусто, никаких действий не производится Члены класса инициализируются константными значениями, в данном сл чае целым значением 0 для переменной feet и вещественным значением 0.0 для переменной inches. Значит, мы можем использовать объекты, инициализируемые с помощью конструктора без параметров, будучи уверенными в том, что поля объекта имеют нулевые, а не другие, случайные, значения. Теперь у нас имеется два явно определенных конструктора с одним и тем же именем Distance(), и поэтому говорят, что конструктор является перегруженным. Какой из этих двух конструкторов исполняется во время создания нового объекта, зависит от того, сколько аргументов используется при вызове: Distance length; //вызывает первый конструктор Distance width(11, 6.0); //вызывает второй конструктор
Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.005 сек.) |