Скотт Майерс - Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ

Тут можно читать онлайн Скотт Майерс - Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ - бесплатно ознакомительный отрывок. Жанр: comp-programming, издательство Литагент «ДМК»233a80b4-1212-102e-b479-a360f6b39df7, год 2006. Здесь Вы можете читать ознакомительный отрывок из книги онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ
  • Автор:
  • Жанр:
  • Издательство:
    Литагент «ДМК»233a80b4-1212-102e-b479-a360f6b39df7
  • Год:
    2006
  • Город:
    Москва
  • ISBN:
    5-94074-304-8
  • Рейтинг:
    3.6/5. Голосов: 101
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5

Скотт Майерс - Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ краткое содержание

Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ - описание и краткое содержание, автор Скотт Майерс, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Эта книга представляет собой перевод третьего издания американского бестселлера Effective C++ и является руководством по грамотному использованию языка C++. Она поможет сделать ваши программы более понятными, простыми в сопровождении и эффективными. Помимо материала, описывающего общую стратегию проектирования, книга включает в себя главы по программированию с применением шаблонов и по управлению ресурсами, а также множество советов, которые позволят усовершенствовать ваши программы и сделать работу более интересной и творческой. Книга также включает новый материал по принципам обработки исключений, паттернам проектирования и библиотечным средствам.

Издание ориентировано на программистов, знакомых с основами C++ и имеющих навыки его практического применения.

Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ - читать онлайн бесплатно ознакомительный отрывок

Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ - читать книгу онлайн бесплатно (ознакомительный отрывок), автор Скотт Майерс
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

В правиле 32 объясняется, что открытое наследование всегда означает «является разновидностью», а в правиле 34 говорится, почему объявление невиртуальной функции в классе определяет инвариант относительно специализации этого класса. Если вы примените эти наблюдения к классам B и D и невиртуальной функции B: mf, то получите следующее:

• Все, что применимо к объектам B, применимо и к объектам D, поскольку каждый объект D также является объектом B;

• Подклассы B должны наследовать как интерфейс, так и реализацию mf, потому что mf невиртуальна в B.

Теперь, если D переопределяет mf, возникает противоречие. Если класс D действительно должен содержать отличную от B реализацию mf и если каждый объект B, являющийся разновидностью B, действительно должен использовать реализацию mf из B, тогда неверно, что каждый объект класса D является разновидностью B. В этом случае D не должен открыто наследовать B. С другой стороны, если класс D действительно должен открыто наследовать B и если D действительно должен содержать реализацию mf, отличную от B, тогда неверно, что mf является инвариантом относительно специализации B. В этом случае mf должна быть виртуальной. И наконец, если каждый объект класса D действительно является разновидностью B и если mf – действительно инвариант относительно специализации B, тогда D, по правде говоря, не нуждается в переопределении mf и не должен пытаться это делать.

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

Если при чтении этого правила у вас возникло ощущение «дежа вю», то, наверное, вы просто вспомнили правило 7, где я объяснял, почему деструкторы в полиморфных базовых классах должны быть виртуальными. Если вы не следуете этому совету (то есть объявляете невиртуальные деструкторы в полиморфных базовых классах), то нарушаете и требование, изложенное в настоящем правиле, потому что все производные классы автоматически переопределяют унаследованную невиртуальную функцию – деструктор базового класса. Это верно даже для производных классов, в которых нет деструкторов, потому что, как объясняется в правиле 5, компилятор генерирует деструктор автоматически, если вы не определяете его сами. По существу, правило 7 – это лишь частный случай настоящего правила, хотя и заслуживает отдельного внимания и рекомендаций по применению.

Что следует помнить

• Никогда не переопределяйте наследуемые невиртуальные функции.

Правило 37: Никогда не переопределяйте наследуемое значение аргумента функции по умолчанию

Давайте с самого начала упростим обсуждение. Есть только два типа функций, которые можно наследовать: виртуальные и невиртуальные. Но переопределять наследуемые невиртуальные функции в любом случае ошибочно (см. правило 36), поэтому мы вполне можем ограничить наше обсуждение случаем наследования виртуальной функции со значением аргумента по умолчанию.

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

Что это значит? Вы говорите, что уже позабыли, в чем заключается разница между статическим и динамическим связыванием? (Кстати, статическое связывание называют еще ранним связыванием, а динамическое – поздним.) Что ж, давайте освежим вашу память.

Статический тип объекта – это тип, объявленный вами в тексте программы. Рассмотрим следующую иерархию классов:

// классы для представления геометрических фигур

class Shape {

public:

enum ShapeColor { Red, Green, Blue };

// все фигуры должны предоставлять функцию для рисования

virtual void draw(ShapeColor color = Red) const = 0;

...

};

class Rectangle: public Shape {

public:

// заметьте, другое значение параметра по умолчанию – плохо!

virtual void draw(ShapeColor color = Green) const;

...

};

class Circle: public Shape {

public:

virtual void draw(ShapeColor color) const;

...

};

Графически это можно представить так:

Теперь рассмотрим следующие указатели Shape ps статический тип Shape - фото 8

Теперь рассмотрим следующие указатели:

Shape *ps; // статический тип – Shape*

Shape *pc = new Circle; // статический тип – Shape*

Shape *pr = new Rectangle; // статический тип – Shape*

В этом примере ps, pc и pr объявлены как указатели на Shape, так что для всех них он и будет выступать в роли статического типа. Отметим, что не совершенно безразлично, на что они указывают в действительности, – независимо от этого они имеют статический тип Shape*.

Динамический тип объекта определяется типом того объекта, на который он ссылается в данный момент. Иными словами, динамический тип определяет поведение объекта. В приведенном выше примере динамический тип pc – это Circle*, а динамический тип pr – Recangle*. Что касается ps, то он не имеет динамического типа, потому что не указывает ни на какой объект (пока).

Динамические типы, как следует из их названия, могут изменяться в процессе работы программы, обычно вследствие присваивания:

ps = pc; // динамический тип ps теперь Circle*

ps = pr; // динамический тип ps теперь Rectangle*

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

pc->draw(Shape::Red); // вызывается Circle::draw(Shape::Red)

pr->draw(Shape::Red); // вызывается Rectangle::draw(Shape::Red)

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

pr->draw(); // вызывается Rectangle::draw(Shape::Red)!

В этом случае динамический тип pr – это Rectangle*, поэтому, как вы и ожидали, вызывается виртуальная функция класса Rectangle. Для функции Rectangle::draw значение аргумента по умолчанию – Green. Но поскольку статический тип pr – Shape*, то значения аргумента по умолчанию берутся из класса Shape, а не Rectangle! В результате получаем вызов, состоящий из странной, совершенно неожиданной комбинации объявлений draw из классов Shape и Rectangle.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Скотт Майерс читать все книги автора по порядку

Скотт Майерс - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ отзывы


Отзывы читателей о книге Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ, автор: Скотт Майерс. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x