Программирование >>  Инициализация объектов класса, структура 

1 ... 142 143 144 [ 145 ] 146 147 148 ... 395


(a) void reset( int * );

void (*pf)( void * ) = reset;

(b) int calc( int, int );

int (*pf1)( int, int ) = calc;

(c) extern C int compute( int *, int ); int (*pf3)( int*, int ) = compute;

Какая из следующих инициализаций приводит к ошибке? Почему?

(d) void (*pf4)( const matrix & ) = 0;

9.2. Три шага разрешения перегрузки

Разрешением перегрузки функции называется процесс выбора той функции из множества перегруженных, которую следует вызвать. Этот процесс основывается на указанных при

void f( float, float );

T t1, t

void f(

int, int );

float, float

int main() {

f( t1, t2 );

return 0;

вызове аргументах. Рассмотрим пример:

Здесь в ходе процесса разрешения перегрузки в зависимости от типа T определяется, будет ли при обработке выражения f(t1,t2) вызвана функция f(int,int) или f(float,float) или зафиксируется ошибка.

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

(a) int calc( int, int ); int calc( const int, const int );

(b) int get(); double get();

(c) int *reset( int * ); double *reset( double * ):

(d) extern C int compute( int *, int ); extern C double compute( double *, double );

Упражнение 9.4



void f(); void f( int );

void f( double, double = 3.4 ); void f( char *, char * );

void main() { f( 5.6 ); return 0;

следующем примере:

При разрешении перегрузки функции выполняются следующие шаги:

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

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

3. Находится функция, которая лучше всего соответствует вызову. Рассмотрим последовательно каждый пункт.

На первом шаге необходимо идентифицировать множество перегруженных функций, которые будут рассматриваться при данном вызове. Вошедшие в это множество функции называются кандидатами. Функция-кандидат - это функция с тем же именем, что и вызванная, причем ее объявление видимо в точке вызова. В нашем примере есть четыре таких кандидата: f() , f(int), f(double, double) и f(char*, char*) .

После этого идентифицируются свойства списка переданных аргументов, т.е. их количество и типы. В нашем примере список состоит из двух аргументов типа double.

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

В нашем примере есть две устоявших функции, которые могут быть вызваны с приведенными аргументами:

функция f(int) устояла, потому что у нее есть всего один параметр и существует преобразование фактического аргумента типа double к формальному параметру тина int;

функция f(double,double) устояла, потому что для второго аргумента есть значение по умолчанию, а первый формальный параметр имеет тип double, что в точности соответствует типу фактического аргумента.

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

об этом процессе. Для тех, кто хочет узнать больше, в следующих двух разделах приводится более подробное описание.

Процесс разрешения перегрузки функции состоит из трех шагов, которые м1 покажем на



void print( unsigned int ); void print( const char* );

print() есть такие:

void print( char );

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

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

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

Преобразования типов и их ранжирование более подробно обсуждаются в разделе 9.3. Здесь мы лишь кратко рассмотрим ранжирование преобразований для нашего примера. Для устоявшей функции f(int) должно быть применено приведение фактического аргумента типа double к типу int, относящееся к числу стандартных. Для устоявшей функции f(double,double) тип фактического аргумента double в точности соответствует типу формального параметра. Поскольку точное соответствие лучше стандартного преобразования (отсутствие преобразования всегда лучше, чем его наличие), то наиболее подходящей функцией для данного вызова считается f(double,double) .

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

(Более подробно все шаги разрешения перегрузки функции обсуждаются в разделе 9.4. Процесс разрешения используется также при вызовах перегруженной функции-члена класса и перегруженного оператора. В разделе 15.10 рассматриваются правила разрешения перегрузки, применяем1е к функциям-членам класса, а в разделе 15.11 -правила для перегруженных операторов. При разрешении перегрузки следует также принимать во внимание функции, конкретизированные из шаблонов. В разделе 10.8 обсуждается, как шаблоны влияют на такое разрешение.)

Упражнение 9.5

Что происходит на последнем (третьем) шаге процесса разрешения перегрузки функции?

9.3. Преобразования типов аргументов A

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

точное соответствие. Тип фактического аргумента точно соответствует типу формального параметра. Например, если в множестве перегруженных функций



1 ... 142 143 144 [ 145 ] 146 147 148 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика