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

1 ... 336 337 338 [ 339 ] 340 341 342 ... 395


extern void release( const ZooAnimalS ); extern void release( const BearS );

правильно: release( const BearS )

устоявших будет функция release(const BearS) :

release ( yinYang );

Аналогичное правило применимо и к указателям. При ранжировании стандартных преобразований из указателя на тип производного класса в указатели на типы различных базовых лучшим считается то, для которого базовый класс наименее удален от производного. Это правило распространяется и на тип void*.

Стандартное преобразование в указатель на тип любого базового класса всегда лучше,

void receive( void* );

чем преобразование в void*. Например, если дана пара перегруженных функций:

void receive( ZooAnimal* );

то наилучшей из устоявших для вызова с аргументом типа Panda* будет receive(ZooAnimal*).

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

extern void mumble ( const BearS ); extern void mumble( const EndangeredS );

/* ошибка: неоднозначный вызов:

* может быть выбрана бая из двух функций

* void mumble( const BearS ); * void mumble( const EndangeredS ) ;

ошибочным:

mumble( yinYang );

const char* с помощью конвертера ZooAnimial::operator const char* (), который представляет собой пользовательское преобразование. Так как стандартное преобразование лучше пользовательского, то в качестве наилучшей из устоявших выбирается функция release(const ZooAnimalS) .

При ранжировании различных стандартных преобразований из производного класса в базовые лучшим считается приведение к тому базовому классу, который ближе к производному. Так, показанный ниже вызов не будет неоднозначным, хотя в обоих случаях требуется стандартное преобразование. Приведение к базовому классу Bear лучше, чем к ZooAnimial, поскольку Bear ближе к классу Panda. Поэтому лучшей из



extern void release( const Bear& ); extern void release( const Panda& );

ZooAAnimal za;

ошибка: нет соответствия

неявного преобразования аргумента типа ZooAnimal в тип производного класса:

release( za );

В следующем примере наилучшей из устоявших будет release(const char*) . Это может показаться удивительным, так как к аргументу применена последовательность нользовательских преобразований, в которой участвует конвертер const char* (). Но поскольку неявного приведения от типа базового класса к типу производного не существует, то release(const Bear&) не является устоявшей функцией, так что

Class ZooAnimal { public:

преобразование: ZooAnimal ==> const char* operator const char*();

...

extern void release( const char* ); extern void release( const Bear& );

ZooAnimal za;

za ==> const char*

правильно: release( const char* )

остается только release(const char*) :

release( za );

Упражнение 19.9

Дана такая иерархия классов:

Для разрешения неоднозначности программист может применить явное приведение типа:

mumble( static cast< Bear >( yinYang ) ); правильно

Инициализация объекта производного класса или ссылки на него объектом типа базового, а также преобразование указателя на тип базового класса в указатель на тип производного никогда не выполняются компилятором неявно. (Однако их можно выполнить с помощью явного применения dynamic cast, как мы видели в разделе 19.1.) Для данного вызова не существует наилучшей из устоявших функции, так как нет



class Base1 {

public:

ostreamS print(); void debug(); void writeCn (); void log( string ); void reset( void *);

...

class Base2 { public:

void debug(); void readCn(); void log( double );

...

class MI : public Base1, public Base2 { public:

ostreamS print();

using Base1::reset;

void reset( char * );

using Base2::log;

using Base2::log;

...

MI *pi = new MI;

(a) pi->print(); (c) pi->readCn(); (e) pi->log( num );

Какие функции входят в множество кандидатов для каждого из следующих вызовов:

(b) pi->debug(); (d) pi->reset(0); (f) pi->writeCn();

Упражнение 19.10

class Base { public:

operator int(); operator const char *();

...

class Derived : public Base { public:

operator double();

...

Дана такая иерархия классов: };

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



1 ... 336 337 338 [ 339 ] 340 341 342 ... 395

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