Green-sell.info

Новые технологии
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Класс point c

Класс point c

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

Конструкторы

Если аргумент не указан, то по умолчанию инициализируется точка в начале координат (О, О).

Можно инициализировать точку как дубль другой точки. Например, обращение Point p(q) инициализирует новую точку р с теми же координатами, как и точка q. В этом случае инициализация осуществляется копирующим конструктором по умолчанию (существующем в компиляторе» языка C++), который выполняет копию со всеми элементами.

Векторная арифметика

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

Операция-функция operator[] возвращает координату х текущей точки, если в обращении в качестве индекса координаты было указано значение О, или координату у при указании значения индекса 1:

Операции отношения

Операции отношения == и != используются для определения эквивалентности двух точек:

Операции реализуют лексикографический порядок отношений, когда считается, что точка а меньше точки b, если либо а.х Рис. 1: Разделение плоскости на семь областей направленным отрезком прямой линии

Вначале проверяется ориентация точек p0, p1 и р2, чтобы определить, располагается ли точка р2 слева или справа, или она коллинеарна с отрезком pp1. В последнем случае необходимы дополнительные вычисления, ели векторы a=pl-pO и b=р2-p0 имеют противоположное направление, то точка р2 лежит позади направленного отрезка pp1 если вектор а короче вектора b, то точка р2 расположена после отрезка pp1. В противном случае точка р2 сравнивается с точками p0 и р1 для определения, совпадает ли с одной из этих концевых точек или лежит между ними.

Для удобства предусмотрена несколько иная версия компонентной функции classify, которой в качестве аргумента передается ребро вместо пары точек.

Определение относительного положения точки и прямой линии используется очень часто. В некоторых применениях достаточна более грубая классификация (т. е. достаточно индикации положения точки слева или справа от прямой линии, или просто фиксации совпадения с ней). В других же применениях требуется полная схема этой классификации.

Полярные координаты

Система полярных координат обеспечивает второй способ задания положения точки на плоскости. Полярная ось выходит из точки начала координат 0 и направлена в виде горизонтального луча вправо, как показано рис. 2. Точка а представляется парой чисел (ra, Thetaa). Принимая точку a за вектор, начинающийся в точке начала координат, число ra определяет тину вектора, а Thetaa — его полярный угол (угол, образуемый между вектором а и полярной осью и отсчитываемый в направлении вращения против часовой стрелки).

Соответствие между парами чисел (ra, Thetaa) и точками не является однозначным: множество пар могут представлять одну и ту же точку. Пара (0, Theta) соответствует началу координат для любого значения 0. Более того, пары чисел (r, Theta + 360k) соответствуют одной и той же точке для любого целого числа k.

Точка может быть представлена как в декартовых, так и в полярных

координатах и иногда бывает необходимо переходить от одной системы к другой. Как это очевидно из рис. 2, два выражения

Для использования этого выражения в функции polarAngle необходимо различать квадранты на плоскости и учитывать случай возможного равенства нулю координаты х:

Заметим, что функция polarAngle возвращает значение -1.0, если текущий вектор является нулевым вектором (в противном случае возвращается неотрицательное значение). Это обстоятельство мы используем впоследствии для упрощения описания функции сравнения, основанной на задании полярного угла.

Компонентная функция length возвращает длину текущего вектора

Компонентная функция distance возвращает значение расстояния (со знаком) от текущей точки до ребра. Эту функцию определим ниже.

Полигоном(многоугольником) называется замкнутая ломаная на плоскости. Отрезки ломаной называются ребрами или сторонами полигона, концевые точки отрезков, совпадающие для двух соседних ребер, называются вершинами. Полигон будет простым, если он не пересекает самого себя(или, что то же, в нем нет ‘дыр’). Простой полигон охватывает непрерывную область плоскости, которая считается внутренней частью полигона. Неограниченная область, окружающая простой полигон, образует внешнюю часть, а набор точек, лежащих на самом полигоне, образует границу между этими двумя частями. Класс Polygon описывает простой заполненный многоугольник, т.е. объединение границы и внутренней части простого полигона. Например, если говорится, что точка находится в полигоне, то это означает принадлежность точки либо границе простого полигона, либо его внутренней части.

Класс Vertex (Вершина)

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

Эту схему обеспечивают классы Vertex и Polygon. Полигон хранится в виде циклического списка объектов класса Vertex с двойными связями. Поскольку вершины полигона существуют одновременно как точки на плоскости и узлы в связном списке, класс Vertex формируется на основе класса Point и класса Node. Класс Polygon содержит элемент данных, указывающий на некоторую вершину в связном списке, представляющем полигон. Класс Polygon служит как общедоступный (public) интерфейс для полигонов.

Класс Vertex наследует элементы данных _next и _prev из базового класса Node(узел списка) и х и у из базового класса Point. По соглашению _next указывает на последователя текущей вершины (ее соседа в направлении по часовой стрелке), a _prev — на предшественника текущей вершины (соседа в направлении против часовой стрелки). Более подробно о классе Node можно прочитать в реализации кольцевого списка.

Объект класса Vertex может быть сформирован на основе точки или по ее координатам х и у.

Компонентные функции cw и ccw возвращают указатели на последователя и предшественника текущей вершины соответственно.

Компонентная функция neighbor сообщает, какой из соседей определен параметром rotation, возвращая одно из значений типа перечисления CLOCKWISE или COUNTER_CLOCKWISE

Компонентная функция point возвращает точку на плоскости, в которой находится текущая вершина

Компонентные функции insert , remove и splice соответствуют своим аналогам, определенным в базовом классе Node.

Заметим, что в функциях insert и remove перед выводом производится преобразование возвращаемых значений к типу указатель_на_Vertех. Явное преобразование необходимо здесь потому, что язык C++ не может автоматически преобразовать указатель из базового класса, чтобы указать на объект производного класса. Причина заключается в том, что компилятор языка C++ не может быть уверенным в том, что имеется объект производного класса, на который нужно указать, поскольку объект базового класса не обязательно должен быть частью объекта производного класса (но, с другой стороны, компилятор языка C++ автоматически преобразует указатель на производный класс для указания на объект базового класса, поскольку каждый объект производного класса включает внутри себя объект базового класса).

Последняя компонентная функция Vertex::split будет определена несколько ниже.

Классы и объекты

В данном уроке мы рассмотрим классы в C++ и познакомимся с объектно-ориентированным программированием. Объектно-ориентированное программирование или ООП — это одна из парадигм программирования. Парадигма — это, другими словами, стиль. Парадигма определяет какие средства используются при написании программы. В ООП используются классы и объекты. Все наши предыдущие программы имели элементы разных парадигм: императивной, процедурной, структурной.

Мы можем написать одинаковую программу в разных парадигмах. Парадигмы не имеют чёткого определения и часто пересекаются.

Давайте посмотрим на пример. Допустим, в нашей игре есть танки и они могут стрелять, при стрельбе у них уменьшается боезапас. Как мы можем это смоделировать без ООП:

У нас есть структура, которая содержит поле, представляющее количество снарядов, и есть функция атаки, в которую мы передаём танк. Внутри функции мы меняем количество снарядов. Так может выглядеть игра на языке C: структуры отдельно от функций, которые совершают действия со структурными переменными. Данную ситуацию можно смоделировать по-другому с помощью объектно-ориентированного программирования (Object-Oriented Programming, OOP) — ООП.В ООП действия привязываются к объектам.

Определение классов в C++

Класс — это пользовательский тип данных (также как и структуры). Т.е. тип данных, который вы создаёте сами. Для этого вы пишете определение класса. Определение класса состоит из заголовка и тела. В заголовке ставится ключевое слов class, затем имя класса (стандартный идентификатор C++). Тело помещается в фигурные скобки. В C++ классы и структуры почти идентичны. В языке C в структурах можно хранить только данные, но в C++ в них можно добавить действия.

Читать еще:  Endpoint protection что это

В C++ ключевые слова struct и class очень близки и могут использоваться взаимозаменяемо. У них есть только одно отличие (об этом ниже). Вот как можно определить такой же класс с помощью struct:

Отличие только первом ключевом слове. В одном из прошлых уроков мы уже обсуждали структуры. что мы видим новое? Ключевые слова private и public — это спецификаторы доступа. Также мы видим, что внутри класса мы можем вставлять определения функций.

Определение класса это чертёж. Оно говорит нам из каких данных состоит класс и какие действия он может совершать. т.е. происходит объединение данных и действий в одной сущности.

Переменные и методы класса

Класс состоит из членов класса (class members). Члены класса могут быть переменными (data members) или методами (function members или methods). Переменные класса могут иметь любой тип данных (включая другие структуры и классы). Методы — это действия, которые может выполнять класс. По сути, это обычные функции.

Все методы класса имеют доступ к переменным класса. Обратите внимание, как мы обращаемся к ammo в методе Attack.

Создание объектов класса

Теперь у нас есть свой тип данных и мы можем создавать переменные данного типа. Если после определения структур мы могли создавать структурные переменные, то в случае классов, мы создаём объекты классов (или экземпляры). Разница между классами и структурами только в терминах. Для C++ это почти одно и то же.

Вот так мы можем создать объекты класса Tank и вызвать метод Attack:

t1 и t2 — объекты класса Tank. Для C++ объект класса — это всего-лишь переменная. Тип данных этих переменных — Tank. Ещё раз повторю, что классы (и структуры) позволяют создавать пользовательские типы данных.

В англоязычной литературе создание объектов классов также называется созданием экземпляров — instantiating.

Мы обращаемся к переменным класса и методам с помощью оператора точки (прямой доступ), также как мы обращались к полям структурных переменных.

В нашем примере каждый объект имеет доступ к своей копии ammo. ammo — переменная класса (data member). Attack — метод класса. У каждого объекта своя копия переменных класса, но все объекты одного класса вызывают одни и те же методы.

Размер объекта включает все данные, но не методы

В памяти переменные класса располагаются последовательно. Благодаря этому мы можем создавать массивы объектов и копировать их все вместе (если в классе этих объектов нет динамического выделения памяти). Это будет важно для нас, когда мы начнём работать с графикой в DirectX/OpenGL. Размер объекта класса можно узнать с помощью функции sizeof. При этом в качестве аргумента можно использовать как объект, так и сам класс:

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

Указатель this

Вот как для компилятора выглядит любой метод:

Это просто иллюстрация. В реальности не нужно указывать аргумент (всё что в круглых скобках). Мы автоматически получаем доступ к указателю this. В данном случае его использование перед ammo необязательно, компилятор автоматически привяжет эту переменную к this.

Указатель this нужен, когда методу необходимо вернуть указатель на текущий объект.

Указатели на объекты

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

При использовании ссылки на объект, для доступа к его членам используется оператор прямого доступа (точка), т.е. с ссылкой можно обращаться как с обычным объектом:

Чуть ниже мы увидим один случай, когда не обойтись без ссылок.

Конструктор класса (Constructor)

Конструктор класса — метод, вызываемый автоматически при создании объекта. Он используется для инициализации переменных класса и выделении памяти, если это нужно. По сути это обычный метод. Имя обязательно должно совпадать с именем класса и он не имеет возвращаемого значения. Рассмотрим новый класс:

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

Перегрузка конструктора класса

Перегрузка (overloading) конструктора позволяет создать несколько конструкторов для одного класса с разными параметрами. Всё то же самое, что и при перегрузке функций:

Начальные значения можно задавать в виде списка инициализации. Выше в конструкторе мы инициализировали переменные внутри тела. Список инициализации идёт перед телом конструктора и выглядит так:

В списке инициализации можно задать значение только части переменных класса.

Копирующий конструктор (Copy Constructor)

Без каких-либо действий с нашей стороны мы можем присваивать объектам другие объекты:

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

В копирующем конструкторе всегда используются ссылки. Это обязательно. Параметр point — это объект, стоящий справа от оператора присваивания.

Деструктор класса

Деструктор класса — метод, вызываемый автоматически при уничтожении объекта. Это происходит, например, когда область видимости объекта заканчивается. Деструктор нужно писать явно, если в классе происходит выделение памяти. Соответственно, в деструкторе вам необходимо освободить все указатели.

Допустим в нашем танке есть экипаж, пусть это будет один объект типа Unit. При создании танка мы выделяем память под экипаж. В деструкторе нам нужно будет освободить память:

Имя деструктора совпадает с именем класса и перед ним ставится тильда

. Деструктор может быть только один.

Объектно-ориентированное программирование в C++ (ООП)

Теперь, когда мы представляем что такое классы и объекты, и умеем с ними работать, можно поговорить о объектно-ориентированном программировании. Сам по себе стиль ООП предполагает использование классов и объектов. Но помимо этого, у ООП есть ещё три характерные черты: инкапсуляция данных, наследование и полиморфизм.

Инкапсуляция данных — Encapsulation

Что означает слово Encapsulation? Корень — капсула. En — предлог в. Инкапсуляция — это буквально помещение в капсулу. Что помещается в капсулу? Данные и действия над ними: переменные и функции. Инкапсуляция — связывание данных и функций. Давайте ещё раз взглянем на класс Tank:

Собственно, здесь в класс Tank мы поместили переменную ammo и метод Attack. В методе Attack мы изменяем ammo. Это и есть инкапсуляция: члены класса (данные и методы) в одном месте.

В C++ есть ещё одно понятие, которое связано с инкапсуляцией — сокрытие данных. Сокрытие предполагает помещение данных (переменных класса) в область, в которой они не будут видимы в других частях программы. Для сокрытия используются спецификаторы доступа (access specifiers). Ключевые слова public и private и есть спецификаторы доступа. public говорит, что весь следующий блок будет видим за пределами определения класса. private говорит, что только методы класса имеют доступ к данным блока. Пример:

Здесь мы видим, что объект может получить доступ только к членам класса, находящимся в блоке public. При попытке обратиться к членам класса (и переменным, и методам) блока private, компилятор выдаст ошибку. При этом внутри любого метода класса мы можем обращаться к членам блока private. В методе Move мы изменяем скрытые переменные x и y.

Хороший стиль программирования в ООП предполагает сокрытие всех данных. Как тогда задавать значения скрытых данных и получать доступ к ним? Для этого используются методы setters и getters.

Читать еще:  Как перевернуть видео в презентации powerpoint

Setters and Getters

Setters и Getters сложно красиво перевести на русский. В своих уроках я буду использовать английские обозначения для них. Setter (set — установить) — это метод, который устанавливает значение переменной класса. Getter (get — получить) — метод, который возвращает значение переменной:

Имена не обязательно должны включать Set и Get. Использование setters и getters приводит к увеличению количества кода. Можно ли обойтись без инкапсуляции и объявить все данные в блоке public? Да, можно. Но данная экономия кода имеет свои негативные последствия. Мы будем подробно обсуждать данный вопрос, когда будем говорить об интерфейсах.

Следующая концепция ООП — наследование.

Наследование (Inheritance) в C++

Производный класс не может получить доступ к private членам. Поэтому в классе Unit используется спецификатор protected. Данный спецификатор разрешает доступ к данным внутри класса и внутри дочерних классов, private же разрешает доступ только в методах самого класса.

При наследовании производный класс имеет доступ ко всем членам (public и protected) базового класса. Именно поэтому мы можем вызвать метод Move для объекта типа Archer.

Обратите внимание, как происходит наследование. При определении дочернего класса, после имени ставится двоеточие, слово public и имя базового класса. В следущем уроке мы рассмотрим для чего здесь нужно слово public.

Полиморфизм (Polymorphism)

Наследование открывает доступ к полиморфизму. Poly — много, morph — форма. Это очень мощная техника, которую мы будем использовать постоянно.

Полиморфизм позволяет поместить в массив разные типы данных:

Мы создали массив указателей на Unit. Но C++ позволяет поместить в такой указатель и указатель на любой дочерний классс. Данная техника будет особенно полезна, когда мы изучим виртуальные функции.

Заключение

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

В следующем уроке мы познакомимся с более сложными концепциями, касающимися классов: виртуалье методы, шаблоны, статичные члены. Впоследствии мы увидим, как классы используютя в DirectX.

Единственное отличие между классом и структурой в C++: по умолчанию в структуре используется спецификатор доступа public, а в классе — private. Часто в коде вы будете видеть, что структуры используются без методов, чисто для описания каких-либо сущностей. Но это делать необязательно это всего лишь соглашение.

Класс point c

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

Конструкторы

Если аргумент не указан, то по умолчанию инициализируется точка в начале координат (О, О).

Можно инициализировать точку как дубль другой точки. Например, обращение Point p(q) инициализирует новую точку р с теми же координатами, как и точка q. В этом случае инициализация осуществляется копирующим конструктором по умолчанию (существующем в компиляторе» языка C++), который выполняет копию со всеми элементами.

Векторная арифметика

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

Операция-функция operator[] возвращает координату х текущей точки, если в обращении в качестве индекса координаты было указано значение О, или координату у при указании значения индекса 1:

Операции отношения

Операции отношения == и != используются для определения эквивалентности двух точек:

Операции реализуют лексикографический порядок отношений, когда считается, что точка а меньше точки b, если либо а.х Рис. 1: Разделение плоскости на семь областей направленным отрезком прямой линии

Вначале проверяется ориентация точек p0, p1 и р2, чтобы определить, располагается ли точка р2 слева или справа, или она коллинеарна с отрезком pp1. В последнем случае необходимы дополнительные вычисления, ели векторы a=pl-pO и b=р2-p0 имеют противоположное направление, то точка р2 лежит позади направленного отрезка pp1 если вектор а короче вектора b, то точка р2 расположена после отрезка pp1. В противном случае точка р2 сравнивается с точками p0 и р1 для определения, совпадает ли с одной из этих концевых точек или лежит между ними.

Для удобства предусмотрена несколько иная версия компонентной функции classify, которой в качестве аргумента передается ребро вместо пары точек.

Определение относительного положения точки и прямой линии используется очень часто. В некоторых применениях достаточна более грубая классификация (т. е. достаточно индикации положения точки слева или справа от прямой линии, или просто фиксации совпадения с ней). В других же применениях требуется полная схема этой классификации.

Полярные координаты

Система полярных координат обеспечивает второй способ задания положения точки на плоскости. Полярная ось выходит из точки начала координат 0 и направлена в виде горизонтального луча вправо, как показано рис. 2. Точка а представляется парой чисел (ra, Thetaa). Принимая точку a за вектор, начинающийся в точке начала координат, число ra определяет тину вектора, а Thetaa — его полярный угол (угол, образуемый между вектором а и полярной осью и отсчитываемый в направлении вращения против часовой стрелки).

Соответствие между парами чисел (ra, Thetaa) и точками не является однозначным: множество пар могут представлять одну и ту же точку. Пара (0, Theta) соответствует началу координат для любого значения 0. Более того, пары чисел (r, Theta + 360k) соответствуют одной и той же точке для любого целого числа k.

Точка может быть представлена как в декартовых, так и в полярных

координатах и иногда бывает необходимо переходить от одной системы к другой. Как это очевидно из рис. 2, два выражения

Для использования этого выражения в функции polarAngle необходимо различать квадранты на плоскости и учитывать случай возможного равенства нулю координаты х:

Заметим, что функция polarAngle возвращает значение -1.0, если текущий вектор является нулевым вектором (в противном случае возвращается неотрицательное значение). Это обстоятельство мы используем впоследствии для упрощения описания функции сравнения, основанной на задании полярного угла.

Компонентная функция length возвращает длину текущего вектора

Компонентная функция distance возвращает значение расстояния (со знаком) от текущей точки до ребра. Эту функцию определим ниже.

Полигоном(многоугольником) называется замкнутая ломаная на плоскости. Отрезки ломаной называются ребрами или сторонами полигона, концевые точки отрезков, совпадающие для двух соседних ребер, называются вершинами. Полигон будет простым, если он не пересекает самого себя(или, что то же, в нем нет ‘дыр’). Простой полигон охватывает непрерывную область плоскости, которая считается внутренней частью полигона. Неограниченная область, окружающая простой полигон, образует внешнюю часть, а набор точек, лежащих на самом полигоне, образует границу между этими двумя частями. Класс Polygon описывает простой заполненный многоугольник, т.е. объединение границы и внутренней части простого полигона. Например, если говорится, что точка находится в полигоне, то это означает принадлежность точки либо границе простого полигона, либо его внутренней части.

Класс Vertex (Вершина)

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

Эту схему обеспечивают классы Vertex и Polygon. Полигон хранится в виде циклического списка объектов класса Vertex с двойными связями. Поскольку вершины полигона существуют одновременно как точки на плоскости и узлы в связном списке, класс Vertex формируется на основе класса Point и класса Node. Класс Polygon содержит элемент данных, указывающий на некоторую вершину в связном списке, представляющем полигон. Класс Polygon служит как общедоступный (public) интерфейс для полигонов.

Класс Vertex наследует элементы данных _next и _prev из базового класса Node(узел списка) и х и у из базового класса Point. По соглашению _next указывает на последователя текущей вершины (ее соседа в направлении по часовой стрелке), a _prev — на предшественника текущей вершины (соседа в направлении против часовой стрелки). Более подробно о классе Node можно прочитать в реализации кольцевого списка.

Объект класса Vertex может быть сформирован на основе точки или по ее координатам х и у.

Читать еще:  Как пдф преобразовать в презентацию powerpoint

Компонентные функции cw и ccw возвращают указатели на последователя и предшественника текущей вершины соответственно.

Компонентная функция neighbor сообщает, какой из соседей определен параметром rotation, возвращая одно из значений типа перечисления CLOCKWISE или COUNTER_CLOCKWISE

Компонентная функция point возвращает точку на плоскости, в которой находится текущая вершина

Компонентные функции insert , remove и splice соответствуют своим аналогам, определенным в базовом классе Node.

Заметим, что в функциях insert и remove перед выводом производится преобразование возвращаемых значений к типу указатель_на_Vertех. Явное преобразование необходимо здесь потому, что язык C++ не может автоматически преобразовать указатель из базового класса, чтобы указать на объект производного класса. Причина заключается в том, что компилятор языка C++ не может быть уверенным в том, что имеется объект производного класса, на который нужно указать, поскольку объект базового класса не обязательно должен быть частью объекта производного класса (но, с другой стороны, компилятор языка C++ автоматически преобразует указатель на производный класс для указания на объект базового класса, поскольку каждый объект производного класса включает внутри себя объект базового класса).

Последняя компонентная функция Vertex::split будет определена несколько ниже.

Двумерная графика на C#, классы Graphics, Pen и Brush

На примере графики наглядно видны преимущества ООП, смысл использования классов, их методов и свойств. Добавляя в пространство имен своего проекта соответствующие библиотеки, вы получаете сразу набор инструментов, необходимых для графики. Это графические примитивы (линии, прямоугольники, эллипсы и т.п.), перо для черчения, кисть для закраски и много других полезных объектов и методов.

2D-графика делится, как вы знаете, на растровую и векторную. Растровое изображение — это набор цветных пикселей, заданных в прямоугольной области, хранящихся в файлах *.bmp, *.jpg, *.png и т.п. Самый простой растровый редактор — программа Paint. Векторная графика намного экономнее (по объемам памяти) растровой. Так для рисования прямоугольника достаточно задать координаты двух точек (левого верхнего и правого нижнего углов) и цвет и толщину линии. В этом разделе в основном рассмотрим методы векторной графики.

Пространство имен System.Drawing (Рисование) обеспечивает доступ к функциональным возможностям графического интерфейса GDI+ , используя около 50 (!) классов, в том числе класс Graphics. Чуть позже мы будем использовать дополнительные пространства имен System.Drawing.Drawing2D, System.Drawing.Imaging, System.Drawing.Printing, System.Drawing.Text, расширяющие функциональные возможности библиотеки System.Drawing.

Класс Graphics предоставляет методы рисования на устройстве отображения (другие термины — графический контекст, «холст»). Определимся сразу, на чем мы хотим рисовать. Далее в примерах он обозначается как объект g.

Способы задания «холста»

1. Графический объект — «холст» для рисования на форме Form1 (указатель this) можно задать, например, одним оператором:
Graphics g = this.CreateGraphics();
Примечание. Заметим, что стандартным образом
Graphics g = new Graphics();
создать объект-холст не удается.
На этом операторе генерируется ошибка:
Для типа «System.Drawing.Graphics» не определен конструктор.

2. Еще пример задания графического контекста на визуальном компоненте PictureBox (ящик для рисования) через растровый объект класса Bitmap. В классе Form1 зададим два объекта:
Graphics g; // графический объект — некий холст
Bitmap buf; // буфер для Bitmap-изображения
В конструктор Form1() добавим следующие операторы:
buf = new Bitmap(pictureBox1.Width, pictureBox1.Height); // с размерами
g = Graphics.FromImage(buf); // инициализация g

3. В принципе, иногда (если все графические операции выполняются внутри одной функции) эти четыре строки могут быть заменены одной строкой:
Graphics g = Graphics.FromImage(new Bitmap(pictureBox1.Width, pictureBox1.Height));
После этого можно задать фон холста белым:
g.Clear(Color.White);

4. Еще один пример задания «холста» на форме через дескриптор окна:
Graphics g = Graphics.FromHwnd(this.Handle);
Далее в примерах конкретизируются эти способы.

Объекты других классов из библиотеки System.Drawing

Такие классы, как Rectangle (прямоугольник) и Point (точка) инкапсулируют элементы GDI+. Отметим, что Point вообще то является структурой (struct) с полями x,y. Это уточнение несущественно, так как в C# структуры похожи на классы, a инициализация объекта-структуры point может выглядеть так же, как инициализация объекта-класса:
Point point= new Point();

Класс Pen (перо) используется для рисования линий и кривых, а классы, производные от класса Brush (кисть) используются для закраски замкнутых контуров (см. ниже).

Класс GraphicsPath позволяет задавать последовательность соединенных линий и кривых, класс Region описывает внутреннюю часть графической формы, состоящей из многоугольников и контуров.

Класс Image – абстрактный базовый класс предоставляет функциональные возможности для производных классов Bitmap и Metafile. Bitmap используется для работы с пиксельными изображениями (см. выше пример). Metafile определяет графический метафайл, содержащий записи, описывающие последовательность графических операций, которые могут быть записаны (созданы) и воспроизведены (отображается). Этот класс не наследуется.

Класс Graphics

Он инкапсулирует поверхность рисования GDI+. Этот класс не наследуется. Методов в этом классе огромное количество, поэтому сначала представим их в таблице, а затем рассмотрим некоторые из них с примерами и пояснениями.
В третьем столбце таблицы указывается число перегрузок метода, различающихся набором параметров (используйте интеллектуальную подсказку IntelliSense для выбора нужного Вам варианта метода).

С#: Создание простых классов

Создавая класс, разработчик должен понимать, что он не создает код программы, а разрабатывает структуру и модель поведения какого-либо объекта, который ему будет необходим при дальнейшей разработки программы.
Создавая класс, мы оперируем абстрактными значениями (если мы создаем класс «человек», мы не создаем конкретную личность, а создаем шаблон который будет применим к любой личности.).

Для того, чтобы создать класс Visual Studio:
1. Нажимаем правой кнопкой мыши по проекту.
2. В появившемся меню выбираем пункт Добавить – Класс
3. В появившемся окне указываем имя класса, например, Point.cs.

Так как мы создаем класс Point (точку), то нам необходимо задать те свойства, которые присуще точке, это: координата по X и координата по Y (если говорить про двухмерное пространство).

public— означает, что свойство или метод общедоступно (также возможно значение private и protected, если данное слово опустить, то считается, что указан тип private)
int – говорит о том, что свойство является целым числом

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

Данный код создает точку с именем р и координатой 10;5

Первая строчка данного примера (1) отвечает за создание переменной типа Point, путем вызова конструктора класса Point. В нашем классе на данный момент конструктор не создан, поэтому в строке (1) вызывается конструктор по умолчанию.

Конструктор по умолчанию присутствует в классе всегда, если в нем явно не указан хотя бы один конструктор.

Добавим свой конструктор в данный класс.

Создание конструктора ничем не отличается от создания функций, кроме 2-х исключений:
1. Конструктор- это функция, которая называется точно так же как и класс
2. У конструктора не указывается тип возвращаемого значения.

Так как мы работаем с классом точка, то для ее создания нам необходимо знать 2 координаты, значит наш конструктор, должен принимать 2 аргумента.

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

В нашем конструкторе «a» и «b» это аргументы и они доступны только в рамках той функции, аргументами, которой они являются. X и Y это свойства класса, поэтому мы можем использовать их в любой функции данного класса

Что произойдет, если аргументы нашего конструктора будут не «a» и «b», а «X» и «Y»?

Visual Studio напишет нам ошибку в строчках (1) и (2), связана она с тем, что внутри функции X и Y – это и аргументы функции и свойства класса. Мы должны явно показать, какие из этих переменных являются свойствами класса. Делается это путем приписывания к данной переменной ключевого слова this

Теперь Visual studio понимает какая переменная за что отвечает.

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

Создадим еще один класс Line (Линия)

Для этого повторим шаги 1-3, описанные выше при создании класса Point.
Что такое Линия? Линия- это набор из 2-х точек. Точка же–это 2-е координаты. Таким образом по сути линия-это 4 координаты.

Подумайте, чем неудобна данная реализация?

В предыдущей части, мы реализовали класс Точка, тем самым мы создали новый тип данных, который можем использовать при необходимости. Тем самым нашу Линию можно реализовать следующим образом:

Для тренировки:
1.Напишите конструктор класса Line
2.Реализуйте класс прямоугольник и эллипс.

Ссылка на основную публикацию
ВсеИнструменты
Adblock
detector