более чем для одной функции только если оно сперва описано как перегруженное имя функции. Напрмер:

overload print; void print(int); void print(char*);

Что касается компилятора, единственное общее, что имеют функции с одинаковым именем, это имя. Предположительно, они в каком-то смысле похожи, но в этом язык ни стесняет програмиста, ни помогает ему. Таким образом, перегруженные имена функций – это главным образом удобство записи. Это удобство значительно в случае функций с общепринятыми именами вроде sqrt, print и open. Когда имя семантически значимо, как это имеет место для операций вроде +, * и «« (#6.2) и в случае конструкторов (#5.2.4 и #6.3.1), это удобство становится сщественным. Когда вызывается перегруженная f(), компилятор должен понять, к какой из функций с именем f следует обртиться. Это делается путем сравнения типов фактических парметров с типами формальных параметров всех функций с именем f. Поиск функции, которую надо вызвать, осуществляется за три отдельных шага:

1. Искать функцию соответствующую точно, и использовать ее, если она найдена,

2. Искать соответствующую функцию используя встроенные преобразования и использовать любую найденную функцию и

3. Искать соответствующую функцию используя преобразвания, определенные пользователем (#6.3), и если множество преобразований единственно, использовать найденную функцию.

Например:

overload print(double), print(int);

void f(); (* print(1); print(1.0); *)

Правило точного соответствия гарантирует, что f напечтает 1 как целое и 1.0 как число с плавающей точкой. Ноль, char или short точно соответствуют параметру. Аналогично, float точно соответствует double.

К параметрам функций с перегруженными именами стандарные С++ правила неявного преобразования типа (#с.6.6) примняются не полностью. Преобразования, могущие уничтожить иформацию, не выполняются. Остаются int в long, int в double, ноль в long, ноль в double и преобразования указателей: преобразование ноль в указатель void*, и указатель на произвоный класс в указатель на базовый класс (#7.2.4).

Вот пример, в котором преобразование необходимо:

overload print(double), print(long);

void f(int a); (* print(a); *)

Здесь a может быть напечатано или как double, или как long. Неоднозначность разрешается явным преобразованием типа (или print(long(a)) или print(double(a))).

При этих правилах можно гарантировать, что когда эффетивность или точность вычислений для используемых типов сщественно различаются, будет использоваться простейший алгритм (функция). Например:

overload pow; int pow(int, int); double pow(double, double); // из «math.h» complex pow(double, complex); // из «complex.h» complex pow(complex, int); complex pow(complex, double); complex pow(complex, complex);

Процесс поиска подходящей функции игнорирует unsigned и const.

4.6.8 Незаданное Число Параметров

Для некоторых функций невозможно задать число и тип всех параметров, которые можно ожидать в вызове. Такую функцию описывают завершая список описаний параметров многоточием (...), что означает «и может быть, еще какие-то неописанные параметры». Например:

int printf(char* ...);

Это задает, что в вызове printf должен быть по меньшей мере один параметр, char*, а остальные могут быть, а могут и не быть. Например:

printf(«Hello, world »); printf(«Мое имя %s %s », first_name, second_name); printf(«%d + %d = %d »,2,3,5);

Такая функция полагается на информацию, которая недотупна компилятору при интерпретации ее списка параметров. В случае printf() первым параметром является строка формата, содержащая специальные последовательности символов, позволящие printf() правильно обрабатывать остальные параметры. %s означает «жди параметра char*», а %d означает «жди параметра int». Однако, компилятор этого не знает, поэтому он не может убедиться в том, что ожидаемые параметры имеют соответствущий тип. Например: printf(«Мое имя %s %s »,2);

откомпилируется и в лучшем случае приведет к какой-нбудь странного вида выдаче. Очевиднще хуже, каждый вызов функции с автоматическим объектом класса включает по меньшей мере один вызов программ выделения и освобождения свободной памяти. Это сделало бы также невозможным реализацию inline- функций членов, которые обращаются к данным закрытой части. Более того, такое изменение сделает невозможным совместную компоновку C и С++ программ (поскольку C компилятор обрабатывает struct не так, как это будет делать С++ компилятор). Для С++ это было сочтено неприемлемым.

5.3.2 Законченный Класс

Программирование без сокрытия данных (с применением структур) требует меньшей продуманности, чем программирование со сокрытием данных (с использованием классов). Структуру можно определить не слишком задумываясь о том, как ее предплагается использовать. А когда определяется класс, все внимние сосредотачивается на обеспечении нового типа полным мнжеством операций; это важное смещение акцента. Время, потраченное на разработку нового типа, обычно многократно окупается при разработке и тестировании программы.

Вот пример законченного типа intset, который реализует понятие «множество целых»:

class intset (* int cursize, maxsize; int *x; public: intset(int m, int n); // самое большее, m int'ов в 1..n ~intset();

int member(int t); // является ли t элементом? void insert(int t); // добавить 't' в множество

void iterate(int amp; i) (* i = 0; *) int ok(int amp; i) (* return i«cursize; *) int next(int amp; i) (* return x[i+ +]; *) *);

Чтобы протестировать этот класс, можно создать и распчатать множество случайных целых чисел. Такое множество могло бы быть результатом розыгрыша лотереи. Это простое множество можно также использовать для проверки последовательности цлых на повторы. Но для большинства приложений тип множество должен быть немного более проработанным. Как всегда, возможны ошибки:

#include «stream.h»

void error(char* s) (* cerr «„ 'set: ' «« s «« « “; exit(1); *)

Класс intset используется в main(), которая предполагает два целых параметра. Первый параметр задает число случайных чисел, которые нужно сгенерировать. Второй параметр указывает диапазон, в котором должны лежать случайные целые:

main(int argc, char* argv[]) (* if (argc != 3) error(«ожидается два параметра»); int count = 0; int m = atoi (argv[1]); // число элементов множества int n = atoi(argv[2]); // в диапазоне 1..n intset s(m,n);

while (count«m) (* int t = randint(n);

if (s.member(t)==0) (* s.insert(t); count++; *) *)

print_in_order( amp;s); *)

В программе, для которой требуется два параметра, счечик числа параметров, argc, должен равняться трем, потому что имя программы всегда передается как argv[0]. Функция

extern int atoi(char*);

функция atoi() это стандартная библиотечная функция для преобразования представления целого в виде строки в его внуреннюю (двоичную) форму. Случайные числа генерируются с пмощью стандартной функции rand():

extern int rand(); // Не очень случайные, будьте осторожны

int randint(int u) // в диапазоне 1..u (* int r = rand(); if (r « 0) r = -r; return 1 + r%u ; *)

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

Вы читаете C++
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату