С++ для начинающих


Функции-кандидаты


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

func( args );

или функции-члена с помощью операторов доступа “точка” или “стрелка”:

object.memfunc( args );

pointer->memfunc( args );

В данном разделе мы изучим оба случая.

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

namespace NS {

   class ZooAnimal { /* ... */ };

   void display( const ZooAnimal& );

}

// базовый класс Bear объявлен в пространстве имен NS

class Bear : public NS::ZooAnimal { };



int main() {

   Bear baloo;

   display( baloo );

   return 0;

}

Аргумент baloo имеет тип класса Bear. Кандидатами для вызова display() будут не только функции, объявления которых видимы в точке ее вызова, но также и те, что объявлены в пространствах имен, в которых объявлены класс Bear и его базовый класс ZooAnimal. Поэтому в множество кандидатов добавляется функция display(const ZooAnimal&), объявленная в пространстве имен NS.

Если аргумент имеет тип класса и в определении этого класса объявлены функции-друзья с тем же именем, что и вызванная функция, то эти друзья также будут кандидатами, даже если их объявления не видны в точке вызова (см. раздел 15.10). Если аргумент при наследовании имеет тип класса, у которого есть базовые, то в множество кандидатов добавляются одноименные функции-друзья каждого из них. Предположим, что в предыдущем примере display() объявлена как функция-друг ZooAnimal:


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

class Bear : public ZooAnimal {

public:

   // feeding_time( int ) перегружает экземпляр из класса ZooAnimal

   using ZooAnimal::feeding_time;

   Time feeding_time( int );

   // ...

};

Теперь обе функции feeding_time() находятся в области видимости класса Bear и, следовательно, войдут в множество кандидатов:

// правильно: вызывается ZooAnimal::feeding_time( string )

Winnie.feeding_time( "Winnie" );

В такой ситуации вызывается функция-член feeding_time( string ).

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

class Endangered {

public:

   ostream& print( ostream& );

   // ...

{;

class Bear : public( ZooAnimal ) {

public:

   void print( );

   using ZooAnimal::feeding_time;

   Time feeding_time( int );

   // ...

};

class Panda : public Bear, public Endangered {

public:

   // ...

};

int main()

{

   Panda yin_yang;

   // ошибка: неоднозначность: одна из

   //         Bear::print()

   //         Endangered::print( ostream& )

   yin_yang.print( cout );

   // правильно: вызывается Bear::feeding_time()

   yin_yang.feeding_time( 56 );

}

При поиске объявления функции-члена print() в области видимости класса Panda будут найдены как Bear::print(), так и Endangered::print(). Поскольку они не находятся в одном и том же базовом классе, то даже при разных списках параметров этих функций множество кандидатов оказывается пустым и вызов считается ошибочным. Для исправления ошибки в классе Panda следует определить собственную функцию print(). При поиске объявления функции-члена feeding_time() в области видимости Panda будут найдены ZooAnimal::feeding_time() и Bear::feeding_time() – они расположены в области видимости класса Bear. Так как эти объявления найдены в одном и том же базовом классе, множество кандидатов для данного вызова включает обе функции, а выбирается Bear::feeding_time().


Содержание раздела