|
Программирование >> Инициализация объектов класса, структура
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( 5 6 ); При поиске объявления функции-члена print() в области видимости класса Panda будут найдены как Bear::print() , так и Endangered::print() . Поскольку они не находятся в одном и том же базовом классе, то даже при разных списках параметров этих функций множество кандидатов оказывается пустым и вызов считается ошибочным. Для исправления ошибки в классе Panda следует определить собственную функцию print() . При поиске объявления функции-члена feeding time() в области видимости Panda будут найдены ZooAnimal::feeding time() и Bear::feeding time() - они расположены в области видимости класса Bear. Так как эти объявления найдены в одном и том же базовом классе, множество кандидатов для данного вызова включает обе функции, а выбирается Bear::feeding time() . 19.3.2. Устоявшие функции и последовательности пользовательских преобразований Наследование оказывает влияние и на второй шаг разрешения перегрузки функции: отбор устоявших из множества кандидатов. Устоявшей называется функция, для которой существуют приведения типа каждого фактического аргумента к типу соответственного формального параметра. В разделе 15.9 мы показали, как разработчик класса может предоставить пользовательские преобразования для объектов этого класса, которые неявно вызываются компилятором для трансформации фактического аргумента функции в тип соответственного формального параметра. Пользовательские преобразования бывают двух видов: конвертер или конструктор с одним параметром без ключевого слова class ZooAnimal { public: конвертер: ZooAnimal ==> const char* operator const char* (); ... можем написать следующий конвертер для ZooAnimal: Производный класс Bear наследует его от своего базового ZooAnimal. Если значение типа Bear используется в контексте, где ожидается const char*, то неявно вызывается extern void display( const char* ); Bear yogi; правильно: yogi ==> const char* конвертер для преобразования Bear в const char*: display( yogi ); Конструкторы с одним аргументом без ключевого слова explicit образуют другое множество неявных преобразований: из типа параметра в тип своего класса. Определим class ZooAnimal { public: преобразование: int ==> ZooAnimal ZooAnimal( int ); ... такой конструктор для ZooAnimal: Его можно использовать для приведения значения типа int к типу ZooAnimal. Однако конструкторы не наследуются. Конструктор ZooAnimal нельзя применять для const int cageNumber = 8788l void mumble( const Bear S ); ошибка: ZooAnimal( int ) не используется преобразования объекта в случае, когда целевым является тип производного класса: mumble( cageNumber ); explicit. При наследовании на втором шаге разрешения перегрузки рассматривается более широкое множество таких преобразований. Конвертеры наследуются, как и любые другие функции-члены класса. Например, мы extern void release( const ZooAnimal& ); Panda yinYang; стандартное преобразование: Panda -> ZooAAnimal имеющихся в классе: release( yinYang ); Поскольку аргумент yinYang типа Panda инициализирует ссылку на тип базового класса, то преобразование имеет ранг стандартного. В разделе 15.10 мы говорили, что стандартные преобразования имеют более высокий public Bear, public Endangered наследует ZooA\nimal::operator const char *() class Panda : { Panda yinYang; extern void release( const ZooAnimal& ); extern void release( const char * ); стандартное преобразование: Panda -> ZooAnimal выбирается: release( const ZooA\nimal& ) ранг, чем пользовательские: release( yinYang ); Как release(const char*) , так и release(ZooAnimal&) являются устоявшими функциями: первая потому, что инициализация параметра-ссылки значением аргумента -стандартное преобразование, а вторая потому, что аргумент можно привести к типу Поскольку целевым типом является Bear - тип параметра функции mumble() , то рассматриваются только его конструкторы. 19.3.3. Наилучшая из устоявших функций Наследование влияет и на третий шаг разрешения перегрузки - выбор наилучшей из устоявших функций. На этом шаге ранжируются преобразования типов, с помощью которых можно привести фактические аргументы функции к типам соответственных формальных параметров. Следующие неявные преобразования имеют тот же ранг, что и стандартные (стандартные преобразования рассматривались в разделе 9.3): преобразование аргумента типа производного класса в параметр типа любого из его базовых; преобразование указателя на тип производного класса в указатель на тип любого из его базовых; инициализация ссылки на тин базового класса с помощью l-значения тина производного. Они не являются пользовательскими, так как не зависят от конвертеров и конструкторов,
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |