Стенли Липпман - Язык программирования C++. Пятое издание
- Название:Язык программирования C++. Пятое издание
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2014
- Город:Москва
- ISBN:978-5-8459-1839-0
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стенли Липпман - Язык программирования C++. Пятое издание краткое содержание
Вы держите в руках новое издание популярного и исчерпывающего бестселлера по языку программирования С++, которое было полностью пересмотрено и обновлено под
. Оно поможет вам быстро изучить язык и использовать его весьма эффективными и передовыми способами. В соответствии с самыми передовыми и современными методиками изложения материала авторы демонстрируют использование базового языка и его стандартной библиотеки для разработки эффективного, читабельного и мощного кода.
С самого начала этой книги читатель знакомится со стандартной библиотекой С++, ее самыми популярными функциями и средствами, что позволяет сразу же приступить к написанию полезных программ, еще не овладев всеми нюансами языка. Большинство примеров из книги было пересмотрено так, чтобы использовать новые средства языка и продемонстрировать их наилучшие способы применения. Эта книга — не только проверенное руководство для новичков в С++, она содержит также авторитетное обсуждение базовых концепций и методик языка С++ и является ценным ресурсом для опытных программистов, особенно желающих побыстрей узнать об усовершенствованиях С++11.
Стенли Б. Липпман Жози Лажойе Барбара Э. Му • Узнайте, как использовать новые средства языка С++11 и стандартной библиотеки для быстрого создания надежных программ, а также ознакомьтесь с высокоуровневым программированием
• Учитесь на примерах, в которых показаны передовые стили программирования и методики проектирования
• Изучите принципы и узнайте почему язык С++11 работает именно так
• Воспользуйтесь множеством перекрестных ссылок, способных помочь вам объединить взаимосвязанные концепции и проникнуть в суть
• Ознакомьтесь с современными методиками обучения и извлеките пользу из упражнений, в которых подчеркиваются ключевые моменты, позволяющие избежать проблем
• Освойте лучшие методики программирования и закрепите на практике изученный материал
Исходный код примеров можно загрузить с веб-страницы книги на сайте издательства по адресу: http://www.williamspublishing.com
Язык программирования C++. Пятое издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
На практике необходимость наличия промежуточного базового класса при виртуальном наследовании редко создает проблемы. Обычно иерархия классов, в которой используется виртуальное наследование, разрабатывается сразу и одним лицом (или группой разработчиков). Ситуации, когда разработку виртуального базового класса необходимо поручить независимому производителю, чрезвычайно редки, а разработчик нового базового класса не может внести изменения в существующую иерархию.
Виртуальное наследование влияет на те классы, которые происходят от виртуального базового класса впоследствии; оно не влияет на класс производный непосредственно.
Базовый класс объявляется виртуальным при помощи ключевого слова virtual
в списке наследования:
// порядок расположения ключевых слов public и virtual несуществен
class Raccoon : public virtual ZooAnimal { /* ... */ };
class Bear : virtual public ZooAnimal { /* ... */ };
Здесь класс ZooAnimal
объявлен виртуальным базовым для классов Bear
и Raccoon
.
Спецификатор virtual
заявляет о готовности совместно использовать единый экземпляр указанного базового класса в последующих производных классах. Нет никаких особых ограничителей на классы, используемые как виртуальные базовые классы.
Для наследования от класса, имеющего виртуальный базовый класс, не нужно ничего особенного:
class Panda : public Bear,
public Raccoon, public Endangered {
};
Здесь класс Panda
наследует класс ZooAnimal
через два своих базовых класса — Raccoon
и Bear
. Но поскольку эти классы происходят от класса ZooAnimal
виртуально, у класса Panda
есть только одна часть базового класса ZooAnimal
.
Объектом производного класса можно манипулировать как обычно, при помощи указателя или ссылки на базовый класс, хотя он и является виртуальным. Например, все следующие преобразования для базового класса объекта класса Panda
вполне допустимы:
void dance(const Bear&);
void rummage(const Raccoon&);
ostream& operator<<(ostream&, const ZooAnimal&);
Panda ying_yang;
dance(ying_yang); // ok: передает объект Panda как Bear
rummage(ying_yang); // ok: передает объект Panda как Raccoon
cout << ying_yang; // ok: передает объект Panda как ZooAnimal
Поскольку виртуальному базовому классу соответствует только один совместно используемый внутренний объект, к членам объекта этого базового класса можно обратиться непосредственно и однозначно. Кроме того, если член виртуального базового класса переопределяется только в одной ветви наследования, к этому переопределенному члену класса можно обратиться непосредственно. Если член переопределяется больше чем одним базовым классом, то производный класс вообще должен определить собственную версию этого члена.
Предположим, например, что класс В
определяет члены по имени x
; класс D1
виртуально наследует класс В
, как и класс D2
; а класс D
происходит от классов D1
и D2
. Из области видимости класса D
член x
видим через оба своих базовых класса. Есть три возможности использовать член x
через объект класса D
:
• Если член x
не будет определен ни в классе D1
, ни в D2
, то будет использован член класса В
; никакой неоднозначности нет. Объект класса D
содержит только один экземпляр члена x
.
• Если x
является членом класса В
и одного (но не обоих) из классов D1
или D2
, никакой неоднозначности снова нет: версия в производном классе имеет приоритет перед совместно используемым виртуальным базовым классом B
.
• Если член x
определяется и в классе D1
, и в классе D2
, то прямой доступ к этому члену неоднозначен.
Как и в иерархии с невиртуальным множественным наследованием, подобная неоднозначность лучше всего устраняется переопределением члена в производном классе.
Упражнение 18.28. Рассмотрим следующую иерархию класса. Можно ли в классе vmi
обращаться к унаследованным членам без уточнения? Какие из них требуют полностью квалифицированных имен? Объясните, почему.
struct Base {
void bar(int); // по умолчанию открыты
protected:
int ival;
};
struct Derived1 : virtual public Base {
void bar(char); // по умолчанию открыты
void foo(char);
protected:
char cval;
};
struct Derived2 : virtual public Base {
void foo(int); // по умолчанию открыты
protected:
int ival;
char cval;
};
class VMI : public Derived1, public Derived2 { };
18.3.5. Конструкторы и виртуальное наследование
При виртуальном наследовании виртуальный базовый класс инициализируется конструктором самого последнего производного класса . В рассматриваемом примере при создании объекта класса Panda
инициализацию членов базового класса ZooAnimal
контролирует конструктор класса Panda.
Чтобы понять это правило, рассмотрим происходящее при применении обычных правил инициализации. В этом случае объект виртуального базового класса мог бы быть инициализирован несколько раз. Он был бы инициализирован вдоль каждой ветви наследования, содержащей этот виртуальный базовый класс. В данном примере, если бы к классу ZooAnimal
применялись обычные правила инициализации, то части Bear
и Raccoon
инициализировали бы часть ZooAnimal
объекта класса Panda
.
Конечно, каждый базовый класс в иерархии объекта мог бы в некоторый момент быть "более производным". Поскольку вполне можно создавать независимые объекты класса, производного от виртуального базового класса, конструкторы в этом классе должны инициализировать его виртуальный базовый класс. Например, когда в рассматриваемой иерархии создается объект класса Bear
(или Raccoon
), никакого дальнейшего применения производного класса нет. В данном случае конструкторы класса Bear
(или Raccoon
) непосредственно инициализируют базовую часть ZooAnimal
, как обычно:
Bear::Bear(std::string name, bool onExhibit) :
ZooAnimal(name, onExhibit, "Bear") { }
Raccoon::Raccoon(std::string name, bool onExhibit) :
ZooAnimal(name, onExhibit, "Raccoon") { }
Когда создается объект класса Panda, он является наиболее производным типом и контролирует инициализацию совместно используемого базового класса ZooAnimal
. Даже при том, что класс ZooAnimal
не является прямым базовым классом для класса Panda
, часть ZooAnimal
инициализирует конструктор класса Panda
:
Интервал:
Закладка: