|
Программирование >> Инициализация объектов класса, структура
object.memfunc( args ); или функции-члена с помощью операторов доступа точка или стрелка : pointer->memfunc( args ); В данном разделе мы изучим оба случая. Если аргумент обычной функции имеет тип класса, ссылки или указателя на тип класса, и класс определен в пространстве имен, то кандидатами будут все одноименные функции, объявленные в этом пространстве, даже если они невидимы в точке вызова (подробнее об этом говорилось в разделе 15.10). Если аргумент при наследовании имеет тип класса, ссылки или указателя на тип класса, и у этого класса есть базовые, то в множество кандидатов добавляются также функции, объявленные в тех пространствах имен, где namespace NS { class ZooAnimal { /* void display( const ZooAnimalS ); базов класс Bear объявлен в пространстве имен NS class Bear : public NS::ZooAnimal { }; int main() { Bear baloo; display( baloo ); return 0; определены базовые классы. Например: 2. Отбор устоявших функций. 3. Выбор наилучшей из устоявших функции. Отбор функций-кандидатов зависит от наследования потому, что на этом шаге принимаются во внимание функции, ассоциированные с базовыми классами, - как их функции-члены, так и функции, объявленные в тех же пространствах имен, где определены базовые классы. Отбор устоявших функций также зависит от наследования, поскольку множество преобразований формальных параметров функции в фактические аргументы расширяется пользовательскими преобразованиями. Кроме того, наследование оказывает влияние на ранжирование последовательностей трансформаций аргументов, а значит, и на выбор наилучшей из устоявших функции. В данном разделе мы рассмотрим влияние наследования на эти три шага разрешения перегрузки более подробно. 19.3.1. Функции-кандидаты Наследование влияет на первый шаг процедуры разрешения перегрузки функции -формирование множества кандидатов для данного вызова, причем это влияние может быть различным в зависимости от того, рассматривается ли вызов обычной функции вида func( args ); namespace NS { class ZooAnimal { friend void display( const ZooAnimal& ); базов класс Bear объявлен в пространстве имен NS class Bear : public NS::ZooAnimal { }; int main() { Bear baloo; display( baloo ); return 0; предыдущем примере display() объявлена как функция-друг ZooAnimal: Аргумент baloo функции display() имеет тип Bear. В его базовом классе ZooAnimal функция display() объявлена другом, поэтому она является членом пространства имен NS, хотя явно в нем не объявлена. При обычном просмотре NS она не была бы найдена. Однако поскольку аргумент display() имеет тип Bear, то объявленная в ZooAnimal функция-друг добавляется в множество кандидатов. Таким образом, если при вызове обычной функции задан аргумент, который представляет собой объект класса, ссылку или указатель на объект класса, то множество функций-кандидатов является объединением следующих множеств: функций, видим1х в точке вызова; функций, объявленных в тех пространствах имен, где определен тин класса или любой из его базовых; функций, являющихся друзьями этого класса или любого из его базовых. Наследование влияет также на построение множества кандидатов для вызова функции-члена с помощью операторов точка или стрелка . В разделе 18.4 мы говорили, что объявление функции-члена в производном классе не перегружает, а скрывает одноименные функции-члены в базовом, даже если их списки параметров различны: Аргумент baloo имеет тин класса Bear. Кандидатами для вызова display() будут не только функции, объявления которых видимы в точке ее вызова, но также и те, что объявлены в пространствах имен, в которых объявлены класс Bear и его базовый класс ZooAnimial. Поэтому в множество кандидатов добавляется функция display(const ZooAnimial&), объявленная в пространстве имен NS. Если аргумент имеет тип класса и в определении этого класса объявлены функции-друзья с тем же именем, что и вызванная функция, то эти друзья также будут кандидатами, даже если их объявления не видны в точке вызова (см. раздел 15.10). Если аргумент при наследовании имеет тип класса, у которого есть базовые, то в множество кандидатов добавляются одноименные функции-друзья каждого из них. Предположим, что в class ZooAnimal { public: Time feeding time( string ); ... class Bear : public ZooAnimal { public: скрает ZooAnimal::feeding time( string ) Time feeding time( int ); ... Bear Winnie; ошибка: ZooAnimal::feeding time( string ) скрыта Winnie.feeding time( Winnie ); Функция-член feeding time(int), объявленная в классе Bear, скрывает feeding time(string) , объявленную в ZooAnimal, базовом для Bear. Поскольку функция-член вызывается через объект Winnie типа Bear, то при поиске кандидатов для этого вызова просматривается только область видимости класса Bear, и единственным кандидатом будет feeding time(int). Так как других кандидатов нет, вызов считается ошибочным. Чтобы исправить ситуацию и заставить компилятор считать одноименные функции-члены базового и производного классов перегруженными, разработчик производного класса может ввести функции-члены базового класса в область видимости производного class Bear : public ZooAnimal { public: feeding time( int ) перегружает экземпляр из класса ZooAnimal using ZooAnimal::feeding time; Time feeding time( int ); ... с помощью using-объявлений: Теперь обе функции feeding time() находятся в области видимости класса Bear и, правильно: вызается ZooAnimal::feeding time( string ) следовательно, войдут в множество кандидатов: Winnie.feeding time( Winnie ); В такой ситуации вызывается функция-член feeding time( string ) . В случае множественного наследования при формировании совокупности кандидатов объявления функций-членов должны быть найдены в одном и том же базовом классе, иначе вызов считается ошибочным. Например:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |