» » » » Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

На нашем литературном портале можно бесплатно читать книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп, Бьёрн Страуструп . Жанр: Программирование. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале litmir.org.
Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Название: Программирование. Принципы и практика использования C++ Исправленное издание
Дата добавления: 22 август 2024
Количество просмотров: 99
Читать онлайн

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту readbookfedya@gmail.com для удаления материала

Программирование. Принципы и практика использования C++ Исправленное издание читать книгу онлайн

Программирование. Принципы и практика использования C++ Исправленное издание - читать бесплатно онлайн , автор Бьёрн Страуструп

Специальное издание самой читаемой и содержащей наиболее достоверные сведения книги по C++. Книга написана Бьярне Страуструпом — автором языка программирования C++ — и является каноническим изложением возможностей этого языка.
Помимо подробного описания собственно языка, на страницах книги вы найдете доказавшие свою эффективность подходы к решению разнообразных задач проектирования и программирования. Многочисленные примеры демонстрируют как хороший стиль программирования на С-совместимом ядре C++, так и современный -ориентированный подход к созданию программных продуктов. Третье издание бестселлера было существенно переработано автором. Результатом этой переработки стала большая доступность книги для новичков. В то же время, текст обогатился сведениями и методиками программирования, которые могут оказаться полезными даже для многоопытных специалистов по C++. Не обойдены вниманием и нововведения языка: стандартная библиотека шаблонов (STL), пространства имен (namespaces), механизм идентификации типов во время выполнения (RTTI), явные приведения типов (cast-операторы) и другие.
Настоящее специальное издание отличается от третьего добавлением двух новых приложений (посвященных локализации и безопасной обработке исключений средствами стандартной библиотеки), довольно многочисленными уточнениями в остальном тексте, а также исправлением множества опечаток.
Книга адресована программистам, использующим в своей повседневной работе C++. Она также будет полезна преподавателям, студентам и всем, кто хочет ознакомиться с описанием языка «из первых рук».

Перейти на страницу:
class="code">Point в раздел private, чтобы защитить его от нежелательных изменений. Для того чтобы он был полезным, мы должны обеспечить доступ к нему.

void Shape::set_point(int i, Point p) // не используется

{

  points[i] = p;

}

Point Shape::point(int i) const

{

  return points[i];

}

int Shape::number_of_points() const

{

  return points.size();

}

В производном классе эти функции используются так:

void Lines::draw_lines() const

// рисует линии, соединяющие пары точек

{

  for (int i=1; i<number_of_points(); i+=2)

    fl_line(point(i–1).x,point(i–1).y,point(i).x,point(i).y);

}

 

 Все эти тривиальные функции доступа могут вызвать у вас обеспокоенность. Эффективны ли они? Не замедляют ли работу программы? Увеличивают ли они размер генерируемого кода? Нет, компилятор всех их делает подставляемыми. Вызов функции number_of_points() занимает столько же байтов памяти и выполняет точно столько же инструкций, сколько и непосредственный вызов функции points.size().

Решения, касающиеся управления доступом, очень важны. Теперь мы могли бы создать почти минимальную версию класса Shape.

struct Shape { // слишком простое определение — не используется

  Shape();

  void draw() const; // работает с цветом и вызывает функцию

                     // draw_lines

  virtual void draw_lines() const;   // рисует линии

  virtual void move(int dx, int dy); // перемещает фигуры +=dx

                                     // и +=dy

  vector<Point> points; // не используется всеми фигурами

  Color lcolor;

  Line_style ls;

  Color fcolor;

}

 

 Какие возможности обеспечивают эти двенадцать дополнительных функций-членов и два канала доступа к спецификациям (private: и protected:)? Главный ответ состоит в том, что защита класса от нежелательного изменения позволяет разработчику создавать лучшие классы с меньшими усилиями. Этот же аргумент относится и к инвариантам (см. раздел 9.4.3). Подчеркнем эти преимущества на примере определения классов, производных от класса Shape. В более ранних вариантах класса Shape мы использовали следующие переменные:

Fl_Color lcolor;

int line_style;

Оказывается, это очень ограничивает наши возможности (стиль линии, задаваемый переменной типа int, не позволяет элегантно задавать ширину линии, а класс Fl_Color не предусматривает невидимые линии) и приводит к довольно запутанному коду. Если бы эти две переменные были открытыми и использовались в пользовательской программе, то мы могли бы улучшить интерфейсную библиотеку только за счет взлома этого кода (поскольку в нем упоминаются имена lcolor и line_style).

 

 Кроме того, функции доступа часто обеспечивают удобство обозначений. Например, инструкция s.add(p) читается и записывается легче, чем s.points.push_back(p). 

14.2.3. Рисование фигур

Мы описали почти все, кроме ядра класса Shape.

void draw() const; // работает с цветом и вызывает функцию

                   // draw_lines

virtual void draw_lines() const; // рисует линии

Основная задача класса Shape — рисовать фигуры. Мы не можем удалить из класса Shape все остальные функции и оставить его вообще без данных о нем самом, не нанеся вреда нашей основной концепции (см. раздел 14.4); рисование — это главная задача класса Shape. Он выполняет ее с помощью библиотеки FLTK и операционной системы, но с точки зрения пользователя он выполнят только две функции.

• Функция draw() интерпретирует стиль и цвет, а затем вызывает функцию draw_lines().

• Функция draw_lines() подсвечивает пиксели на экране.

Функция draw() не использует никаких новаторских методов. Она просто вызывает функции библиотеки FLTK, чтобы задать цвет и стиль фигуры, вызывает функцию draw_lines(), чтобы выполнить реальное рисование на экране, а затем пытается восстановить цвет и фигуру, заданные до ее вызова.

void Shape::draw() const

{

  Fl_Color oldc = fl_color();

  // универсального способа идентифицировать текущий стиль

  // не существует

  fl_color(lcolor.as_int());            // задаем цвет

  fl_line_style(ls.style(),ls.width()); // задаем стиль

  draw_lines();

  fl_color(oldc);   // восстанавливаем цвет (предыдущий)

  fl_line_style(0); // восстанавливаем стиль линии (заданный

                    // по умолчанию)

}

 

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

 

 Обратите внимание на то, что функция Shape::draw() не работает с цветом заливки фигуры и не управляет видимостью линий. Эти свойства обрабатывают отдельные функции draw_lines(), которые лучше “знают”, как их интерпретировать. В принципе всю обработку цвета и стиля можно было бы перепоручить отдельным функциям draw_lines(), но для этого пришлось бы повторять много одних и тех же фрагментов кода.

Рассмотрим теперь, как организовать работу с функцией draw_lines(). Если немного подумать, то можно прийти к выводу, что функции-члену класса Shape было бы трудно рисовать все, что необходимо для создания любой разновидности фигуры. Для этого пришлось бы хранить в объекте класса Shape каждый пиксель каждой фигуры. Если мы используем вектор vector<Point>, то вынуждены хранить огромное количество точек. И что еще хуже, экран (т.е. устройство для вывода графических изображений) лучше “знает”, как это делать.

 

 Для того чтобы избежать лишней работы и сохранять лишнюю информацию, примем другой подход: дадим каждому классу, производному от класса Shape, возможность самому определить, что он будет рисовать. Классы Text, Rectangle и Circle лучше “знают”, как нарисовать свои объекты. На самом деле все такие классы это “знают”. Помимо всего прочего, такие классы точно “знают” внутреннее представление информации. Например, объект класса Circle определяется точкой и радиусом, а не, скажем, отрезком линии. Генерирование требуемых битов для объекта класса Circle на основе точки и радиуса там, где это необходимо, и тогда, когда это необходимо, не слишком сложная и затратная работа. По этой причине в классе Circle определяется своя собственная функция draw_lines(), которую мы хотим вызывать, а не функция draw_lines() из класса Shape. Именно это означает слово virtual в объявлении функции Shape::draw_lines().

struct Shape {

  // ...

  virtual void

Перейти на страницу:
Комментариев (0)