Выбрать главу

19.3.2. Устоявшие функции и последовательности пользовательских преобразований

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

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

Конвертеры наследуются, как и любые другие функции-члены класса. Например, мы можем написать следующий конвертер для ZooAnimaclass="underline"

class ZooAnimal {

public:

// конвертер: ZooAnimal == const char*

operator const char*();

// ...

};

Производный класс Bear наследует его от своего базового ZooAnimal. Если значение типа Bear используется в контексте, где ожидается const char*, то неявно вызывается конвертер для преобразования Bear в const char*:

extern void display( const char* );

Bear yogi;

// правильно: yogi == const char*

display( yogi );

Конструкторы с одним аргументом без ключевого слова explicit образуют другое множество неявных преобразований: из типа параметра в тип своего класса. Определим такой конструктор для ZooAnimaclass="underline"

class ZooAnimal {

public:

// преобразование: int == ZooAnimal

ZooAnimal( int );

// ...

};

Его можно использовать для приведения значения типа int к типу ZooAnimal. Однако конструкторы не наследуются. Конструктор ZooAnimal нельзя применять для преобразования объекта в случае, когда целевым является тип производного класса:

const int cageNumber = 8788l

void mumble( const Bear & );

// ошибка: ZooAnimal( int ) не используется

mumble( cageNumber );

Поскольку целевым типом является Bear – тип параметра функции mumble(), то рассматриваются только его конструкторы.

19.3.3. Наилучшая из устоявших функций

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

* преобразование указателя на тип производного класса в указатель на тип любого из его базовых;

* инициализация ссылки на тип базового класса с помощью l-значения типа производного.

Они не являются пользовательскими, так как не зависят от конвертеров и конструкторов, имеющихся в классе:

extern void release( const ZooAnimal& );

Panda yinYang;

// стандартное преобразование: Panda - ZooAnimal

release( yinYang );

Поскольку аргумент yinYang типа Panda инициализирует ссылку на тип базового класса, то преобразование имеет ранг стандартного.

В разделе 15.10 мы говорили, что стандартные преобразования имеют более высокий ранг, чем пользовательские:

class Panda : public Bear,

public Endangered

{

// наследует ZooAnimaclass="underline" :operator const char *()

};

Panda yinYang;

extern void release( const ZooAnimal& );

extern void release( const char * );

// стандартное преобразование: Panda - ZooAnimal

// выбирается: release( const ZooAnimal& )

release( yinYang );

Как release(const char*), так и release(ZooAnimal&) являются устоявшими функциями: первая потому, что инициализация параметра-ссылки значением аргумента – стандартное преобразование, а вторая потому, что аргумент можно привести к типу const char* с помощью конвертера ZooAnimaclass="underline" :operator const char*(), который представляет собой пользовательское преобразование. Так как стандартное преобразование лучше пользовательского, то в качестве наилучшей из устоявших выбирается функция release(const ZooAnimal&).