Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
63
Добавлен:
16.02.2016
Размер:
455 Кб
Скачать

Перегрузка функций

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

int func(int, int)

и

int func(int&, int&)

приведет к ошибке, так как с точки зрения перегрузки они счита­ются одинаковыми. По той же причине аргументы функции, от­носящиеся к некоторому типу, модифицированные const или volatile, не рассматриваются как отличные от базового типа с точки зрения перегрузки. Указатели на const- и volatile-объекты также не рассматриваются как отличные от указателей на базовый тип с точки зрения перегрузки. Однако механизм пе­регрузки может различать ссылки, которые имеют модификаторы const и volatile, и ссылки на базовый тип. Например, сле­дующий код вполне допустим:

#include <iostream.h>

class AnyClass

{

public:

AnyClass()

{cout «"Конструктор по умолчанию "«"для AnyClass" « "\n";} AnyClass(AnyClassS ob)

{cout «"Конструктор копирования для " « "AnyClass" « "\n";}

AnyClass(const AnyClassS ob)

{cout «"Конструктор копирования для" « "AnyClass" « "\n";}

};

main()

{

AnyClass ob1;

AnyClass оb2(ob1);

const AnyClass оb3;

AnyClass оb4(оb3);

}

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

• любые две перегруженные функции должны иметь раз­личные списки параметров;

• перегрузка функций с совпадающими списками аргумен­тов на основе лишь типа возвращаемых ими значений не­допустима;

• функции-члены не могут быть перегружены исключи­тельно на основе того, что одна из них является статиче­ской, а другая - нет;

• typedef-определения не влияют на механизм перегруз­ки, так как они не вводят новых типов данных, а опреде­ляют лишь синонимы для существующих типов. Напри­мер, следующее определение

typedef char* PSTR;

не позволит компилятору рассматривать две приведенные ниже функции –

void SetVal(char* sz) ;

и

void SetVal(PSTR sz);

как различные. Поэтому их одновременное объявление в классе вызовет ошибку;

• все enum-типы данных рассматриваются как различные и могут использоваться для различения перегруженных функций;

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

void SetVal(char sx);

void SetVal(char* psz);

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

void SetVal(char szStr[]);

void SetVal(char szStr[][4]);

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

#include <iostream.h>

void func(int i)

{

cout « "Вызов глобально объявленной "«"функции:"« i « endl;

}

void func(char* str)

{

cout «"Вызов локально объявленной " « "функции:" « str « endl;

}

main ()

{

extern void func(char*);

//Следующий вызов функции вызовет ошибку

func(100);

//А это - верно

func("переопределение!");

return 0;

}

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

class AnyClass

{

public:

AnyClass();

double MembFunc(double, char*);

private:

int MembFunc(int);

};

double

AnyClass:: MembFunc(double, char*)

{

//Тело функции

}

int

AnyClass:: MembFunc(int)

{

//Тело функции

}

main()

{

AnyClass* pCl = new AnyClass;

//Следующая инструкция вызовет ошибку, т.к. она содержит вызов private-функции

рСl-> MembFunc(104);

//А здесь - все верно, т.к. вызывается publiс-функция

рСl-> MembFunc(104.22, "строковый аргумент");

delete pCl;

return 0;

}

Концептуально можно перегружать и статические функции-члены класса, хотя это не имеет большого смысла. Ниже приве­ден пример перегруженной статической функции-члена.

class AnyClass

{

public:

static void SetVal(int);

static void SetVal(double);

private:

static int x;

static double y;

};

int AnyClass::x = 0;

double AnyClass::у = 0;

void AnyClass::SetVal(int _x){x = _x;}

void AnyClass::SetVal(double _y){y = _y;}

main ()

{

AnyClass::SetVal(10);

AnyClass::SetVal(10.4567);

return 0;

}

Соседние файлы в папке ЯзыкС++Глушаков