Г. Шилтд - Самоучитель C++ (PDF) (1114887), страница 7
Текст из файла (страница 7)
Хотя такое отличие от С на первый взгляд кажетсязначительным, на самом деле это не так. Фактически оно совершеннопрозрачно и вот почему: как вы знаете, в С любое ненулевое значениеявляется истинным, а нулевое — ложным. В C++ это положение сохраняется, поскольку при использовании таких значений в булевом выражении ненулевое значение автоматически преобразуется в true, а нулевое —в false. Правильно и обратное: true преобразуется в 1, a false в 0, еслизначение типа bool оказывается в целом выражении.
Добавление в C++данных типа bool усиливает контроль типа и дает возможность различатьданные булева и целого типов. Естественно, что использование данныхбулева типа не обязательно, скорее оно просто удобно.ПримерыР1. В программах С, при отсутствии в командной строке аргументов, функцияmain() обычно объявляется так:intmain(void)Однако в C++ такое использование слова void избыточно и необязательно.2. Эта короткая программа C++ не будет компилироваться, поскольку у функции sum() нет прототипа:// Эта программа не будет компилироваться^include <iostream>using namespace std;intmain()(int a,b,c;cout « "Введите два числа: ";cin » a » b;c=sum(a, b);cout « "Сумма равна:" « с;Глава1.КраткийобзорC++_35return 0;// Этой функции необходим прототипsum{int a, int b){return a+b;3.
Эта короткая программа иллюстрирует тот факт, что локальные переменныеможно объявить в любом месте блока:ttinclude <iostrearn>using namespace std;int main ( ){int i; // локальная переменная, объявленная в начале блокаcout « "Введите число:";cin » i;// расчет факториалаint j, fact=l; // переменные, объявленные перед инструкциями// действияfor (j=i; j>=l; j — ) fact=fact * j ;cout « "Факториал равен:" « fact;return 0;Хотя объявление переменных j и fact рядом с местом их первого использования в этом коротком примере и не слишком впечатляет, в больших функциях такая возможность может обеспечить программе ясность и предотвратитьнежелательные побочные эффекты.4. В следующей Программе создается булева переменная outcome и ей присваивается значение false.
Затем эта переменная используется в инструкции if.^include <iostream>using namespace std;int m a i n ( )bool outcome;outcome = false;if(outcome) cout « "истина";else cout « "ложь";36_СамоучительC++return 0;Как и следовало ожидать, в результате выполнения программы на экранепоявляется слово ложь.ения)Упражнения1. Следующая программа не будет компилироваться в качестве программыC++. Почему?// В этой программе есть ошибка#include <iostream>using namespace std;intmain()ft);return 0;)ivoid f ()cout « "Программа работать не будет";2. Попытайтесь объявлять локальные переменные в различных местах программы C++.
Попытайтесь проделать то же с программой С, обращая вниманиена то, какие объявления вызовут сообщения об ошибках.1.7. Введение в перегрузку функцийПосле классов, вероятно, следующей важной и необычной возможностьюC++ является перегрузка функций (function overloading). Перегрузка функций не только обеспечивает механизм, посредством которого в C++ достигается один из типов полиморфизма, она также формирует то ядро, вокруг которого развивается вся среда программирования на C+ + . Ввидуважности темы в данном разделе предлагается только предварительноезнакомство с перегрузкой функций, которой посвящена целая глава этойкниги.В C++ две или более функции могут иметь одно и то же имя, отличаясьлибо типом, либо числом своих аргументов, либо и тем и другим. Если двеили более функции ;::.ао! ,;д™мпковос имя. говорят, что они перегружены.Глава7.КраткийобзорC++_37Перегруженные функции позволяют упростить программы, допуская обращение к одному имени для выполнения близких по смыслу действий.Перегрузить функцию очень легко: просто объявите и определите все требуемые варианты.
Компилятор автоматически выберет правильный вариант вызова на основании числа и/или типа используемых в функции аргументов.В C++ можно также перегружать и операторы. Однако для того чтобы понятьперегрузку операторов, необходимо больше узнать о C++.ПримерыОдно из основных применений перегрузки функций — это достижение полиморфизма при компиляции программ, который воплощает в себе философию — один интерфейс, множество методов. Как вы знаете, при программировании на С необходимо иметь определенное число близких по назначениюфункций, отличающихся только типом данных, с которыми они работают.Классический пример этой ситуации дает набор библиотечных функций С.Как ранее упоминалось в этой главе, библиотека содержит функции abs(),labs() и fabs(), которые возвращают абсолютное значение, соответственно,целого, длинного целого и числа с плавающей точкой.
Однако из-за того,что для трех типов данных требуется три типа функции, ситуация выглядитболее сложной, чем это необходимо. Во всех трех случаях возвращается абсолютная величина числа, отличие только в типе данных. В то же время,программируя на C++, вы можете исправить эту ситуацию путем перегрузкиодного имени для трех типов данных так, как показано в следующем примере:#include <iostream>using namespace std;// Перегрузка a b s ( ) тремя способамиint abs(int n ) ;long abs(long n ) ;double abs(double n ) ;intmain()cout « "Абсолютная величина -10:" « abs (-10) « " \ n / n " ;cout « "Абсолютная величина -10L:" « abs (-10L) « " \ n / n " ;cout « "Абсолютная величина -10.01:" « abs (-10.
01) « "\n/n";return 0;38_СамоучительC++II abs {) для целыхint abs (int n){cout « "В целом abs()\n";return n<0 ? -n: n;}// abs() для длинных целыхlong abs (long n){cout « "В длинном целом abs()\n";return n<0 ? -n: n;}// abs() для вещественных двойной точностиdouble abs (double n}{cout « "В вещественном abs() двойной точности \n";return n<0 ? -n: n;Как можно заметить, в программе задано три функции abs(), своя для каждого типа данных. Внутри main() функция abs() вызывается с тремя аргументами разных типов. Компилятор автоматически вызывает правильную версиюabs(), основываясь на используемом в аргументе типе данных. В результатеработы программы на экран выводится следующее:В целом abs ( )Абсолютная величина -10:В длинном целом abs ( )Абсолютная величина -10L:1010В вещественном abs() двойной точностиАбсолютная величина -10.01: 10.01Хотя этот пример достаточно прост, ценность перегрузки функций он все жедемонстрирует.
Поскольку одно имя используется для описания основного набора действий, искусственная сложность, вызванная тремя слабо различающимися именами, в данном случае abs(), labsQ и fabs(), устраняется. Теперь вамнеобходимо помнить только одно имя — то, которое описывает общее действие. На компилятор возлагается задача выбора соответствующей конкретнойверсии вызываемой функции (а значит и метода обработки данных). Это имеетлавинообразный эффект в вопросе снижения сложности программ.
В данномслучае, благодаря использованию полиморфизма, из трех имен получилосьодно.Хотя использование полиморфизма в этом примере довольно тривиально,вы, должно быть, уже поняли, что для очень больших программ подход"один интерфейс, множество методов" может быть очень эффективным.Глава 1. Краткий обзор C++39_2.
Ниже приведен другой пример перегрузки функций. В этом случае функцияdate() перегружается для получения даты либо в виде строки, либо в видетрех целых. В обоих этих случаях функция выводит на экран переданные ейданные.ttinclude <iostream>using namespace std;void date(char *date); // дата в виде строкиvoid date(int month, int day, int y e a r ) ; // дата в виде чиселint main{){date("8/23/99");date( 8, 23, 9 9 ) ;return 0;// Дата в виде строкиvoid date (char *date){cout « "Дата:" « date « "\n";}// Дата в виде целыхvoid date (int month, int day, int year){cout « "Дата:" « month « "/";cout « day « "/"•« year « "\n";Этот пример показывает, как перегрузка функций может обеспечить дляфункции более понятный интерфейс.
Поскольку дату очень естественнопредставлять либо в виде строки, либо в виде трех целых чисел, содержащихмесяц, день и год, нужно просто выбрать наиболее подходящую версию в соответствии с ситуацией.3. До сих пор мы рассматривали перегруженные функции, отличающиеся типом своих аргументов. Однако перегруженные функции могут также отличаться и числом аргументов, как показано в приведенном ниже примере:ttinclude <iostream>using namespace std;void f l ( i n t a ) ;void fl(int a, int b);int main{)fl(10, 2 0 ) ;40return 0;}void f l ( i n t a)cout « "B f l ( i n t a) \n";void f l f i n t a,int b)cout « "B f l ( i n t a, int b) \n'4.
Важно понимать, что тип возвращаемого значения сам по себе еще не является достаточным отличием для перегрузки функции. Если две функции отличаются только типом возвращаемых данных, компилятор не всегда сможетвыбрать нужную. Например, следующий фрагмент неправилен, поскольку внем имеет место избыточность:// Это все неправильно и не будет компилироватьсяint fl{int a);double fl{int а);f1 (10); // какую функцию выбрать компилятору???Как написано в комментарии, у компилятора нет способа выяснить, какуюверсию fl{) вызвать.Упражнения1. Создайте функцию sroot(), которая возвращает квадратный корень своегоаргумента. Перегрузите sroot() тремя способами: чтобы получить квадратныйкорень целого, длинного целого и числа с плавающей точкой двойной точности.