Главная | Форум | Статьи | Фaйлы| Картинки WoW | Профиль | Регистрация | Вход

[ Новые сообщения · Правила форума · Поиск · RSS ]

WoW-Info — информационный World of Warcraft портал

Перегруженные функции - Форум

  • Сторінка 1 з 1
  • 1
Перегруженные функции
МинусочегДата: Четвер, 13.01.2011, 11:24 | Сообщение # 1



Минусочег
©~Бессмертный~©
Сержант
Группа: V.I.P
Сообщений: 121

Замечания:

Оффлайн
Итак, мы уже знаем, как объявлять, определять и использовать функции в программах. В этой главе речь пойдет об их специальном виде – перегруженных функциях. Две функции называются перегруженными, если они имеют одинаковое имя, объявлены в одной и той же области видимости, но имеют разные списки формальных параметров. Мы расскажем, как объявляются такие функции и почему они полезны. Затем мы рассмотрим вопрос об их разрешении, т.е. о том, какая именно из нескольких перегруженных функций вызывается во время выполнения программы. Эта проблема является одной из наиболее сложных в C++. Тем, кто хочет разобраться в деталях, будет интересно прочитать два раздела в конце главы, где тема преобразования типов аргументов и разрешения перегруженных функций раскрывается более подробно.

9.1. Объявления перегруженных функций

Теперь, научившись объявлять, определять и использовать функции в программах, познакомимся с перегрузкой – еще одним аспектом в C++. Перегрузка позволяет иметь несколько одноименных функций, выполняющих схожие операции над аргументами разных типов.
Вы уже воспользовались предопределенной перегруженной функцией. Например, для вычисления выражения

Code
1 + 3

вызывается операция целочисленного сложения, тогда как вычисление выражения

Code
1.0 + 3.0

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

9.1.1. Зачем нужно перегружать имя функции

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

Code
int i_max( int, int );
int vi_max( const vector<int> & );
int matrix_max( const matrix & );

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

Code
int ix = max( j, k );
vector<int> vec;
//...
int iy = max( vec );

Этот подход оказывается чрезвычайно полезным во многих ситуациях.

9.1.2. Как перегрузить имя функции

В C++ двум или более функциям может быть дано одно и то же имя при условии, что их списки параметров различаются либо числом параметров, либо их типами. В данном примере мы объявляем перегруженную функцию max():

Code
int max ( int, int );
int max( const vector<int> & );
int max( const matrix & );

Для каждого перегруженного объявления требуется отдельное определение функции max() с соответствующим списком параметров.
Если в некоторой области видимости имя функции объявлено более одного раза, то второе (и последующие) объявление интерпретируется компилятором так:

  • если списки параметров двух функций отличаются числом или типами параметров, то функции считаются перегруженными:

    Code
    // перегруженные функции
           void print( const string & );
           void print( vector<int> & );

  • если тип возвращаемого значения и списки параметров в объявлениях двух функций одинаковы, то второе объявление считается повторным:

    Code
    // объявления одной и той же функции
           void print( const string &str );
           void print( const string & );

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

    Code
      unsigned int max( int i1, int i2 ); int max( int i1, int i2 );  
           // ошибка: отличаются только типы
           // возвращаемых значений

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

    Code
    // объявления одной и той же функции
    int max ( int *ia, int sz );
    int max ( int *ia, int = 10 );

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

    Code
    // typedef не вводит нового типа
    typedef double DOLLAR;
    // ошибка: одинаковые списки параметров, но разные типы
    // возвращаемых значений
    extern DOLLAR calc( DOLLAR );
    extern int calc( double );

    Спецификаторы const или volatile при подобном сравнении не принимаются во внимание. Так, следующие два объявления считаются одинаковыми:

    Code
    // объявляют одну и ту же функцию
    void f( int );
    void f( const int );

    Спецификатор const важен только внутри определения функции: он показывает, что в теле функции запрещено изменять значение параметра. Однако аргумент, передаваемый по значению, можно использовать в теле функции как обычную инициированную переменную: вне функции изменения не видны. (Способы передачи аргументов, в частности передача по значению, обсуждаются в разделе 7.3.) Добавление спецификатора const к параметру, передаваемому по значению, не влияет на его интерпретацию. Функции, объявленной как f(int), может быть передано любое значение типа int, равно как и функции f(const int). Поскольку они обе принимают одно и то же множество значений аргумента, то приведенные объявления не считаются перегруженными. f() можно определить как

    Code
    void f( int i ) { }

    или как

    Code
    void f( const int i ) { }

    Наличие двух этих определений в одной программе – ошибка, так как одна и та же функция определяется дважды.
    Однако, если спецификатор const или volatile применяется к параметру указательного или ссылочного типа, то при сравнении объявлений он учитывается.

    Code
    // объявляются разные функции
    void f( int* );
    void f( const int* );

    // и здесь объявляются разные функции
    void f( int& );
    void f( const int& );

    9.1.3. Когда не надо перегружать имя функции

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

    Code
    void setDate( Date&, int, int, int );
    Date &convertDate( const string & );
    void printDate( const Date& );

    Эти функции работают с одним типом данных – классом Date, но выполняют семантически различные действия. В этом случае лексическая сложность, связанная с употреблением различных имен, проистекает из принятого программистом соглашения об обеспечении набора операций над типом данных и именования функций в соответствии с семантикой этих операций. Правда, механизм классов C++ делает такое соглашение излишним. Следовало бы сделать такие функции членами класса Date, но при этом оставить разные имена, отражающие смысл операции:

    Code
    #include <string>
    class Date {
    public:
        set( int, int, int );
        Date& convert( const string & );
        void print();

        // ...
    };

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

    Code
    Screen& moveHome();
    Screen& moveAbs( int, int );
    Screen& moveRel( int, int, char *direction );
    Screen& moveX( int );
    Screen& moveY( int );

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

    Code
    // функция, объединяющая moveX() и moveY()
    Screen& move( int, char xy );

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

    Code
    // какой вызов понятнее?
    myScreen.home(); // мы считаем, что этот!
    myScreen.move();

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

    Code

    moveAbs(int, int);
    moveAbs(int, int, char*);

    различаются наличием третьего параметра типа char*. Если их реализации похожи и для третьего аргумента можно найти разумное значение по умолчанию, то обе функции можно заменить одной. В данном случае на роль значения по умолчанию подойдет указатель со значением 0:

    Code
    move( int, int, char* = 0 );

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



  • Собираю не + а МИНУСА! P.s "+" за мою работу не ставить!! Только МИНУСА
     
    • Сторінка 1 з 1
    • 1
    Пошук:

    Новые сообщения в темах
    Сдам в аренду сервер и хостинг · (Хост Предложения)
    Автор: redlaine
    Последнее сообщение в 23:53
    хаха :D · (Приколы)
    Автор: [N1ke]Medved
    Последнее сообщение в 18:40
    Autobattle - новый боевой бот ... · (Боты для WoW)
    Автор: terrikon
    Последнее сообщение в 18:39
    PvE руководство для Чернокнижн... · (Чернокнижник)
    Автор: Darkensand
    Последнее сообщение в 18:38
    Пустой свиток (Часть 11) · (Истории WoW)
    Автор: R_a_Z_o_R
    Последнее сообщение в 18:37
    Друиды в Катаклизме: Официальн... · (Друид)
    Автор: Darkensand
    Последнее сообщение в 18:37
    [Баг 3.3.5] Фарм ледяных бадже... · (Читы для WoW)
    Автор: Darkensand
    Последнее сообщение в 18:35
    FarmBot (Бот для фарма руды и ... · (Боты для WoW)
    Автор: homma
    Последнее сообщение в 18:34
    Почему мы сражаемся: ролевая и... · (Воин)
    Автор: Darkensand
    Последнее сообщение в 18:34
    Книги по Wold of Warcraft · (Истории WoW)
    Автор: R_a_Z_o_R
    Последнее сообщение в 18:33
    Маг огня в Cataclysm · (Маг)
    Автор: Darkensand
    Последнее сообщение в 18:33
    Как начать играть в World of W... · (Полезно знать)
    Автор: Belkmondesh
    Последнее сообщение в 18:32
    Характеризация профессий · (Профессии)
    Автор: Darkensand
    Последнее сообщение в 18:31
    Что значит для арканов бета те... · (Маг)
    Автор: Darkensand
    Последнее сообщение в 18:31

    Контакты Контакты Copyright WoW-Info — World of Warcraft портал © 2025 | Условия и правила использования ресурса | Реклама / Услуги
    WoW-Info портал.World of Warcraft портал — готовые сервера, сайты, картинки, аддоны, патчи, читы, баги, mangos, ArcEmu, TrinityCore, Warcraft 3, новости, Cataclysm...
    Яндекс.Метрика Хостинг від uCoz