// конструктор по умолчанию класса Bear вызывается до
// конструктора класса Endangered с двумя аргументами ...
Panda::Panda()
: Endangered( Endangered::environment,
Endangered::critical )
{ ... }
то все равно конструктор по умолчанию Bear был бы вызван раньше, чем явно заданный в списке конструктор класса Endangered с двумя аргументами.
Порядок вызова деструкторов всегда противоположен порядку вызова конструкторов. В нашем примере деструкторы вызываются в такой последовательности: ~Panda(), ~Endangered(), ~Bear(), ~ZooAnimal().
В разделе 17.3 уже говорилось, что в случае одиночного наследования к открытым и защищенным членам базового класса можно обращаться напрямую (не квалифицируя имя члена именем его класса), как если бы они были членами производного класса. То же самое справедливо и для множественного наследования. Однако при этом можно унаследовать одноименные члены из двух или более базовых классов. В таком случае прямое обращение оказывается неоднозначным и приводит к ошибке компиляции.
Однако такую ошибку вызывает не потенциальная неоднозначность неквалифицированного доступа к одному из двух одноименных членов, а лишь попытка фактического обращения к нему (см. раздел 17.4). Например, если в обоих классах Bear и Endangered определена функция-член print(), то инструкция
ying_yang.print( cout );
приводит к ошибке компиляции, даже если у двух унаследованных функций-членов разные списки параметров.
Error: ying_yang.print( cout ) -- ambiguous, one of
Bear::print( ostream& )
Endangered::print( ostream&, int )
Ошибка: ying_yang.print( cout ) -- неоднозначно, одна из
Bear::print( ostream& )
Endangered::print( ostream&, int )
Причина в том, что унаследованные функции-члены не образуют множество перегруженных функций внутри производного класса (см. раздел 17.3). Поэтому print() разрешается только по имени, а не по типам фактических аргументов. (О том, как производится разрешение, мы поговорим в разделе 18.4.)