Объектно ориентированное программирование в c: Псевдо ООП в C / Хабр
Содержание
Радченко Глеб Игоревич
Научные интересы
- Грид-вычисления.
- Облачные вычисления.
- Распределенные вычислительные системы.
Публикации
Проекты
- Проект Erasmus+ PWs@PhD. Основная цель проекта PWs@PhD – поддержка развития, модернизации, интернационализации высшего образования, а именно исследовательской составляющей европейского образования уровня PhD, содействие созданию новых PhD-программ в странах-партнерах в области программной инженерии.
- Сервисно-ориентированный подход к использованию проблемно-ориентированных пакетов в распределенных и грид-средах (проект DiVTB).
- Параллельная реализация нейросетевого алгоритма распознавания раздельной речи (Часть 1, Часть 2, Часть 3).
Новости
- [2013-12-25] Обновления страниц курсов:
- [2013-12-17] Обновления страниц курсов:
- [2013-11-28] Обновления страниц курсов:
- [2013-11-07] Размещены слайды презентаций:
- [2013-10-26] Размещены слайды презентаций:
- [2013-06-03] Размещены слайды презентаций:
[Архив новостей]
Ссылки
- Mendeley — система для каталогизации и управления библиографией. Встраивается в Microsoft Word, позволяя автоматизировать процесс управления списками литературы при подготовке статей. Поддерживает множество форматов оформления библиографических ссылок, включая ГОСТ-7.0.5-2008.
- Memsource — операционная среда для выполнения письменных переводов, включающая базы памяти переводов, встроенный машинный перевод, модуль управления терминологией, а также текстовый редактор MemSource Editor. Может импортировать и экспортировать документы всех стандартных форматов, включая Word и PowerPoint.
Мой профиль
Объектно-ориентированное программирование (С++)|ИТММ ННГУ
Кафедра информатики и автоматизации научных исследований
Специальность: Прикладная информатика
Преподаватель: Филимонов А.В.
Целями освоения дисциплины (модуля) «Объектно-ориентированное программирование (С++)» являются получение знаний и практических навыков программирования на языке С++ в рамках объектно-ориентированного программирования.
В курсе приводятся основные аспекты объектно-ориентированного программирования (ООП), даются основы языка С++, как средства реализации объектно-ориентированной парадигмы. Даются основные понятия и конструкции языка, методы реализации базовых операций. Рассматривается способ реализации объектно-ориентированной парадигмы средствами языка С++.
В результате освоения дисциплины обучающийся должен:
Знать: основы терминологии, конструкции (синтаксис, операции, работа с указателями, базовые библиотеки) языка С++, базовые принципы применения языка.
Уметь: Писать программы на языке С++ с использованием одного из компиляторов и одного из визуальных средств разработки.
Владеть: основными принципами компиляции, выполнения и отладки программ на С++ на основе одной из визуальных сред разработки.
Содержание
1. БАЗОВЫЕ ЗНАНИЯ О С++
Начальные сведения о языке. История создания языка и его эволюция. Международный стандарт языка. Сферы применения языка Си++. Пример простой программы. Объясняется процесс ее написания, использования простейших конструкций языка, использования транслятора и запуск программы на выполнение.
Имена, переменные и константы. Правила именования переменных и функций языка, правила записи констант. Понятие ключевого или зарезервированного слова, список ключевых слов Си++.
Операции и выражения. Правила формирования и вычисления выражений в языке Си++. Все операции языка.
Операторы. Описываются все операторы управления, имеющиеся в языке Си++, даются примеры их использования.
Функции. Функции – это основные единицы построения программ при процедурном программировании на языке Си++. Правила их записи, вызова и передачи параметров.
Встроенные типы данных. Рассматриваются все встроенные типы языка Си++: целые числа разной разрядности, вещественные числа, логические величины, перечисляемые значения, символы и их кодировка.
2. КЛАССЫ И ОБЪЕКТЫ.
Классы и объекты. Способы описания классов. Создание объектов. Обращение к атрибутам и методам объектов.
Производные типы данных. Создание и использование массивов, структур, объединений, указателей. Адресная арифметика. Строки и литералы.
Распределение памяти. Проблемы при явном распределении памяти в Си++, способы их решения. Ссылки и указатели. Распределение памяти под переменные, управление памятью с помощью переопределения операторов new и delete.
Производные классы, наследование. Наследование, виды наследования. Виртуальные методы. Абстрактные классы. Множественное наследование.
Контроль доступа к объекту. Рассматриваются возможности контроля доступа к атрибутам и методам объекта, контроль по чтению и по записи.
Классы – конструкторы и деструкторы. Конструкторы и деструкторы классов. Возможности инициализации объектов. Копирующий конструктор. Операции new и delete.
Дополнительные возможности классов. Рассматриваются дополнительные возможности при определении классов, включая переопределение операций, определение методов inline и задание собственных преобразований типа.
3. КОМПОНОВКА ПРОГРАММ, ПРЕПРОЦЕССОР
Компоновка программ, препроцессор. Компоновка программ, возможности, позволяющие писать большие программы.
Определение, время жизни и области видимости переменных в больших программах
Возможности построения больших программ, использование общих данных. Определение контекста, оператор namespace.
4. ОБРАБОТКА ОШИБОК, ШАБЛОНЫ
Обработка ошибок. Попытка классификации ошибок. Сообщение об ошибке с помощью возвращаемого значения. Исключительные ситуации. Обработка исключительных ситуаций, операторы try и catch.
Ввод-вывод. Потоки. Манипуляторы и форматирование ввода-вывода. Строковые потоки. Ввод-вывод файлов.
Шаблоны. Понятие шаблона. Функции-шаблоны. Шаблоны классов. Примеры использования.
Лабораторный практикум
- Простейшая программа на С++. Среда разработки Visual Studio. Ввод программы, компиляция, выполнение.
- Арифметические операции и математические функции языка С
- Битовые операции
- Работа с матрицами. Структуры и массивы структур
- Указатели, массивы, символьные строки и функции
- Классы, объекты и их ассоциации.
- Наследование и ограничение видимости
- Обработка ошибок и шаблоны
Литература
а) основная литература:
- Г. Шилдт — C++. Руководство для начинающих
- Г. Шилдт — Самоучитель C++
б) дополнительная литература:
- Роберт Седжвик — Фундаментальные алгоритмы на C++. Части 1-4. Анализ. Структуры данных. Сортировка. Поиск
Отчетность
Курс «Объектно-ориентированное программирование на языке С++»
Актуальность | Идёт набор |
---|---|
Стоимость | 20 000 руб |
Продолжительность | 72 часа |
Группа | от 8 до 10 человек |
Начало занятий | По мере формирования группы |
Записаться на курс
Основной задачей курса является приобретение слушателями знаний об объектно-ориентированном подходе в программировании, освоение возможностей языка С++ с концентрацией на решении объектно-ориентированных проблем.
В процессе обучения осуществляется знакомство с объектно-ориентированным программированием как с технологией программирования. На примерах рассматривается синтаксис языка С++, классы, интерфейсы, конструкторы, дружественные функции и перегрузка операций, производные классы, классы потоков С++, шаблоны функций, шаблоны классов, параметры шаблонов, наследование и шаблоны. Особое внимание при обучении уделяется приемам обработки исключительных ситуаций в С++.
Цель реализации программы: качественное изменение профессиональных компетенций, необходимых для выполнения следующих видов профессиональной деятельности в рамках имеющейся квалификации:
- Знать концепцию объектно-ориентированного программирования, основные ее понятия (класс, объект), свойства (инкапсуляция, наследование, полиморфизм), методику анализа и проектирования объектно-ориентированных программ, основные понятия, синтаксис и семантику конструкций языка программирования С++, способы составления объектно-ориентированных программ на языке программирования С++, возможности интегрированной среды программирования на языке С++;
- Уметь проектировать, программировать и отлаживать объектно-ориентированные программы на языке С++;
- Иметь представление об объектно-ориентированных расширениях современных языков программирования, инструментальных программных средствах ООП; тенденциях развития и областях применения ООП.
Категория слушателей – высшее образование, САПР, программирование
Форма обучения – без отрыва от работы
Учебный план
№ п/п | Наименование разделов | Всего часов | В том числе | |||
---|---|---|---|---|---|---|
Лекции | Практические и лабораторные занятия | Самостоятельное изучение | Проверка знаний | |||
1
|
Раздел 1. Введение в язык программирования С++
|
12
|
3
|
9
|
|
|
|
|
2
|
|
|
|
2
|
2
|
Раздел 2. Объекты и Классы. Перегрузка операций. Виртуальные функции.
|
21
|
6
|
15
|
|
|
|
|
2
|
|
|
|
2
|
3
|
Раздел 3. Наследование классов. Обработка исключительных ситуаций
|
10
|
2
|
8
|
|
|
4
|
Раздел 4. Шаблоны. Стандартная библиотека шаблонов (STL)
|
12
|
4
|
8
|
|
|
|
|
2
|
|
|
|
2
|
5
|
Раздел 5. С++ 11
|
10
|
2
|
8
|
|
|
|
|
2
|
|
|
|
2
|
|
Итого:
|
72
|
17
|
47
|
|
8
|
6
|
Итоговая аттестация
|
зачет
|
Контактная информация
Запись на курс
Объектно-ориентированное программирование | Программирование на C и C++
Объектно-ориентированное программирование представляет собой путь для овладения профессией программиста. С момента изобретения компьютера методологии программирования драматически изменяются, приспосабливаясь к растущей сложности программ. Например, в самом начале компьютерной эры программирование осуществлялось с лицевой панели компьютера путем ввода двоичных машинных инструкций. До тех пор, пока программы содержали не более сотни-другой инструкций, такой подход работал. С ростом программ был изобретен язык Ассемблер, так что программист мог работать с большими и более сложными программами, используя символическое представление для машинных инструкций.
В конце концов были введены языки высокого уровня, дающие программисту больше средств для решения проблемы сложности программ. Первым широко распространенным языком был FORTRAN. Хотя FORTRAN был очень впечатляющим первым шагом, его трудно считать языком, обеспечивающим ясность и легкость понимания программ.
60-е годы дали начало структурному программированию — методу, во многом обязанному таким языкам, как С и Паскаль. Структурированные языки впервые позволили писать относительно сложные программы с достаточной легкостью. Однако, как только проект достигал определенного размера, работать с ним оказывалось трудно, даже при использовании методов структурного программирования.
Вехами в развитии программирования являются методы, которые служат решению проблемы возрастающей сложности программ. На каждом этапе этого пути новый подход включает в себя лучшие элементы предыдущих методов и идет дальше их. В настоящее время многие проекты достигли той точки, где подход структурного программирования более не работает. Для решения возникающих проблем и было изобретено объектно-ориентированное программирование.
Объектно-ориентированное программирование впитало в себя лучшие идеи структурного программирования и комбинирует их с новыми мощными концепциями, позволяющими увидеть задачу программирования в новом свете. Объектно-ориентированное программирование позволяет легко разложить задачу на подгруппы взаимодействующих частей. Затем можно преобразовать эти подгруппы в единицы, называемые объектами.
Все объектно-ориентированные языки имеют три общие концепции: инкапсуляцию, полиморфизм и наследование.
СПИСОК ЛИТЕРАТУРЫ
1. Ашарина, И.В. Объектно-ориентированное программирование в С++: лекции и упражнения: Учебное пособие для вузов / И.В. Ашарина. — М.: РиС, 2015. — 336 c.
|
|
Объектно-ориентированное программирование: на пальцах — Журнал «Код»: программирование без снобизма
Настало время серьёзных тем: сегодня расскажем про объектно-ориентированное программирование, или ООП. Это тема для продвинутого уровня разработки, и мы хотим, чтобы вы его постигли.
Из этого термина можно сделать вывод, что ООП — это такой подход к программированию, где на первом месте стоят объекты. На самом деле там всё немного сложнее, но мы до этого ещё доберёмся. Для начала поговорим про ООП вообще и разберём, с чего оно начинается.
Обычное программирование (процедурное)
Чаще всего под обычным понимают процедурное программирование, в основе которого — процедуры и функции. Функция — это мини-программа, которая получает на вход какие-то данные, что-то делает внутри себя и может отдавать какие-то данные в результате вычислений. Представьте, что это такой конвейер, который упакован в коробочку.
Например, в интернет-магазине может быть функция «Проверить email». Она получает на вход какой-то текст, сопоставляет со своими правилами и выдаёт ответ: это правильный электронный адрес или нет. Если правильный, то true, если нет — то false.
Функции полезны, когда нужно упаковать много команд в одну. Например, проверка электронного адреса может состоять из одной проверки на регулярные выражения, а может содержать множество команд: запросы в словари, проверку по базам спамеров и даже сопоставление с уже известными электронными адресами. В функцию можно упаковать любой комбайн из действий и потом просто вызывать их все одним движением.
Что не так с процедурным программированием
Процедурное программирование идеально работает в простых программах, где все задачи можно решить, грубо говоря, десятком функций. Функции аккуратно вложены друг в друга, взаимодействуют друг с другом, можно передать данные из одной функции в другую.
Например, вы пишете функцию «Зарегистрировать пользователя интернет-магазина». Внутри неё вам нужно проверить его электронный адрес. Вы вызываете функцию «Проверить email» внутри функции «Зарегистрировать пользователя», и в зависимости от ответа функции вы либо регистрируете пользователя, либо выводите ошибку. И у вас эта функция встречается ещё в десяти местах. Функции как бы переплетены.
Тут приходит продакт-менеджер и говорит: «Хочу, чтобы пользователь точно знал, в чём ошибка при вводе электронного адреса». Теперь вам нужно научить функцию выдавать не просто true — false, а ещё и код ошибки: например, если в адресе опечатка, то код 01, если адрес спамерский — код 02 и так далее. Это несложно реализовать.
Вы залезаете внутрь этой функции и меняете её поведение: теперь она вместо true — false выдаёт код ошибки, а если ошибки нет — пишет «ОК».
И тут ваш код ломается: все десять мест, которые ожидали от проверяльщика true или false, теперь получают «ОК» и из-за этого ломаются.
Теперь вам нужно:
- либо переписывать все функции, чтобы научить их понимать новые ответы проверяльщика адресов;
- либо переделать сам проверяльщик адресов, чтобы он остался совместимым со старыми местами, но в нужном вам месте как-то ещё выдавал коды ошибок;
- либо написать новый проверяльщик, который выдаёт коды ошибок, а в старых местах использовать старый проверяльщик.
Задача, конечно, решаемая за час-другой.
Но теперь представьте, что у вас этих функций — сотни. И изменений в них нужно делать десятки в день. И каждое изменение, как правило, заставляет функции вести себя более сложным образом и выдавать более сложный результат. И каждое изменение в одном месте ломает три других места. В итоге у вас будут нарождаться десятки клонированных функций, в которых вы сначала будете разбираться, а потом уже нет.
Это называется спагетти-код, и для борьбы с ним как раз придумали объектно-ориентированное программирование.
Объектно-ориентированное программирование
Основная задача ООП — сделать сложный код проще. Для этого программу разбивают на независимые блоки, которые мы называем объектами.
Объект — это не какая-то космическая сущность. Это всего лишь набор данных и функций — таких же, как в традиционном функциональном программировании. Можно представить, что просто взяли кусок программы и положили его в коробку и закрыли крышку. Вот эта коробка с крышками — это объект.
Программисты договорились, что данные внутри объекта будут называться свойствами, а функции — методами. Но это просто слова, по сути это те же переменные и функции.
Объект можно представить как независимый электроприбор у вас на кухне. Чайник кипятит воду, плита греет, блендер взбивает, мясорубка делает фарш. Внутри каждого устройства куча всего: моторы, контроллеры, кнопки, пружины, предохранители — но вы о них не думаете. Вы нажимаете кнопки на панели каждого прибора, и он делает то, что от него ожидается. И благодаря совместной работе этих приборов у вас получается ужин.
Объекты характеризуются четырьмя словами: инкапсуляция, абстракция, наследование и полиморфизм. Если интересно, что это такое, приглашаем в кат:
Инкапсуляция — объект независим: каждый объект устроен так, что нужные для него данные живут внутри этого объекта, а не где-то снаружи в программе. Например, если у меня есть объект «Пользователь», то у меня в нём будут все данные о пользователе: и имя, и адрес, и всё остальное. И в нём же будут методы «Проверить адрес» или «Подписать на рассылку».
Абстракция — у объекта есть «интерфейс»: у объекта есть методы и свойства, к которым мы можем обратиться извне этого объекта. Так же, как мы можем нажать кнопку на блендере. У блендера есть много всего внутри, что заставляет его работать, но на главной панели есть только кнопка. Вот эта кнопка и есть абстрактный интерфейс.
В программе мы можем сказать: «Удалить пользователя». На языке ООП это будет «пользователь.удалить()» — то есть мы обращаемся к объекту «пользователь» и вызываем метод «удалить». Кайф в том, что нам не так важно, как именно будет происходить удаление: ООП позволяет нам не думать об этом в момент обращения.
Например, над магазином работают два программиста: один пишет модуль заказа, а второй — модуль доставки. У первого в объекте «заказ» есть метод «отменить». И вот второму нужно из-за доставки отменить заказ. И он спокойно пишет: «заказ.отменить()». Ему неважно, как другой программист будет реализовывать отмену: какие он отправит письма, что запишет в базу данных, какие выведет предупреждения.
Наследование — способность к копированию. ООП позволяет создавать много объектов по образу и подобию другого объекта. Это позволяет не копипастить код по двести раз, а один раз нормально написать и потом много раз использовать.
Например, у вас может быть некий идеальный объект «Пользователь»: в нём вы прописываете всё, что может происходить с пользователем. У вас могут быть свойства: имя, возраст, адрес, номер карты. И могут быть методы «Дать скидку», «Проверить заказ», «Найти заказы», «Позвонить».
На основе этого идеального пользователя вы можете создать реального «Покупателя Ивана». У него при создании будут все свойства и методы, которые вы задали у идеального покупателя, плюс могут быть какие-то свои, если захотите.
Идеальные объекты программисты называют классами.
Полиморфизм — единый язык общения. В ООП важно, чтобы все объекты общались друг с другом на понятном им языке. И если у разных объектов есть метод «Удалить», то он должен делать именно это и писаться везде одинаково. Нельзя, чтобы у одного объекта это было «Удалить», а у другого «Стереть».
При этом внутри объекта методы могут быть реализованы по-разному. Например, удалить товар — это выдать предупреждение, а потом пометить товар в базе данных как удалённый. А удалить пользователя — это отменить его покупки, отписать от рассылки и заархивировать историю его покупок. События разные, но для программиста это неважно. У него просто есть метод «Удалить()», и он ему доверяет.
Такой подход позволяет программировать каждый модуль независимо от остальных. Главное — заранее продумать, как модули будут общаться друг с другом и по каким правилам. При таком подходе вы можете улучшить работу одного модуля, не затрагивая остальные — для всей программы неважно, что внутри каждого блока, если правила работы с ним остались прежними.
Плюсы и минусы ООП
У объектно-ориентированного программирования много плюсов, и именно поэтому этот подход использует большинство современных программистов.
- Визуально код становится проще, и его легче читать. Когда всё разбито на объекты и у них есть понятный набор правил, можно сразу понять, за что отвечает каждый объект и из чего он состоит.
- Меньше одинакового кода. Если в обычном программировании одна функция считает повторяющиеся символы в одномерном массиве, а другая — в двумерном, то у них большая часть кода будет одинаковой. В ООП это решается наследованием.
- Сложные программы пишутся проще. Каждую большую программу можно разложить на несколько блоков, сделать им минимальное наполнение, а потом раз за разом подробно наполнить каждый блок.
- Увеличивается скорость написания. На старте можно быстро создать нужные компоненты внутри программы, чтобы получить минимально работающий прототип.
А теперь про минусы:
- Сложно понять и начать работать. Подход ООП намного сложнее обычного процедурного программирования — нужно знать много теории, прежде чем будет написана хоть одна строчка кода.
- Требует больше памяти. Объекты в ООП состоят из данных, интерфейсов, методов и много другого, а это занимает намного больше памяти, чем простая переменная.
- Иногда производительность кода будет ниже. Из-за особенностей подхода часть вещей может быть реализована сложнее, чем могла бы быть. Поэтому бывает такое, что ООП-программа работает медленнее, чем процедурная (хотя с современными мощностями процессоров это мало кого волнует).
Что дальше
Впереди нас ждёт разговор о классах, объектах и всём остальном важном в ООП. Крепитесь, будет интересно!
Объектно-ориентированное программирование — всё по этой теме для программистов
Паттерн ООП «Хранитель»
Обсудим паттерн ООП проектирования Хранитель на примере текстового редактора, который меняет форматирование текста и других элементов
Стоит прочитать: обзор книги Бретта Маклафлина «Объектно-ориентированный анализ и проектирование»
Книга, которая расскажет, как организованы анализ, проектирование и написание серьёзных объектно-ориентированных программ.
Объектно-ориентированное программирование простым языком — объясняют эксперты
Спросили у экспертов, как простыми словами объяснить начинающему программисту, что такое ООП.
Когда применять функциональное программирование, а когда ООП — отвечают эксперты
ООП или функциональное программирование? А может, всё сразу? Узнаём у экспертов, когда нужно применять ту или иную парадигму программирования.
Мнение: объектно-ориентированное программирование — катастрофа на триллион долларов
В статье описаны основные минусы объектно-ориентированного программирования в сравнении с функциональным программированием.
Фундаментальные принципы объектно-ориентированного программирования на JavaScript
Многие привыкли к ООП через классовое наследование. Кто-то использует прототипное, как в JavaScript. А что если есть лучшая альтернатива обоим?
Курс «Объектно-Ориентированное Программирование»
В этом видеокурсе описаны основные аспекты объектно-ориентированного программирования — наиболее широко распространенной сегодня парадигмы программирования. Автор курса — Владимир Моженков, преподаватель со стажем работы в России и Британии.
Введение в ООП с примерами на C#. Часть пятая. Всё о модификаторах доступа
Рассказывает Akhil Mittal В прошлых статьях серии «Введение в ООП» мы рассматривали полиморфизм (а также нюансы использования его на практике), наследование и абстрактные классы. В этой части я постараюсь раскрыть все тонкости…
Введение в ООП с примерами на C#. Часть четвёртая. Абстрактные классы
Рассказывает Akhil Mittal В прошлых статьях серии «Введение в ООП» мы рассматривали полиморфизм (а также его нюансы на практике) и наследование. В этой мы поговорим о самой захватывающей части ООП-парадигмы…
Введение в ООП с примерами на C#. Часть третья. Практические аспекты использования полиморфизма
Рассказывает Akhil Mittal Введение Раньше в этой серии мы говорили о полиморфизме и наследовании. В этой статье мы опять будем говорить о полиморфизме, но в этот раз сосредоточимся именно на практических нюансах, а не…
Введение в ООП с примерами на C#. Часть первая. Все, что нужно знать о полиморфизме
Рассказывает Akhil Mittal Я много писал на смежные темы, вроде концепции MVC, Entity Framework, паттерна «Репозиторий» и т.п. Моим приоритетом всегда было полное раскрытие темы, чтобы читателю не приходилось гуглить…
Шпаргалка по принципам ООП
Чтобы стать программистом, нужно знать принципы ООП как Отче наш. Держите структурированную шпаргалку по объектно-ориентированному программированию. Главное Инкапсулируйте все, что может изменяться; Уделяйте больше внимания интерфейсам, а не их реализациям;…
Введение в ООП с примерами на C#. Часть вторая. Все, что нужно знать о наследовании
Рассказывает Akhil Mittal Вступление В первой статье этой серии мы рассматривали работу разных вариантов реализации перегрузки. В этой части мы сосредоточимся на таком разделе объектно-ориентированного программирования, как наследование.
Чем отличаются наследование и композиция в Java
Несмотря на то, что и композиция, и наследование позволяют использовать код повторно, они делают это по-разному. Основное отличие между ними состоит в том, что композиция позволяет переиспользовать код без его…
oop — объектно-ориентированное программирование на C
oop — объектно-ориентированное программирование на C — qaru
Присоединяйтесь к Stack Overflow , чтобы учиться, делиться знаниями и строить свою карьеру.
Спросил
Просмотрено
6к раз
На этот вопрос уже есть ответы здесь :
Закрыт 10 лет назад.
Возможный дубликат:
Можете ли вы написать объектно-ориентированный код на C?
Привет, может кто-нибудь указать мне на учебник, объясни мне, как концепции ООП могут быть реализованы в ANSI C:
- виртуальные функции
- наследство
- лучшие практики
Книга о программировании ООП на ANSI C тоже была бы отличной.
Создан 23 сен.
Drahnrdrahnr
6,41555 золотых знаков4545 серебряных знаков6969 бронзовых знаков
2
Вот ссылка на книгу по этой теме: http: // www.planetpdf.com/codecuts/pdfs/ooc.pdf (объектно-ориентированное программирование на Ansi-C — именно то, что вы искали).
Удачи и терпения. Написание ООП на C — непростая задача, но может оказаться полезным, если вы любите экстремальные вещи!
Другой отправной точкой будет проверка GObject: http://library.gnome.org/devel/gobject/, и, как сказал @unwind, GTK — хороший пример того, как использовать концепции ООП в C. Вы также можете взять в GLib, — хорошая библиотека, которая, безусловно, сделает вашу жизнь программирования на C намного проще, она запрограммирована в стиле ООП и, как плюс, портативна!
Создан 23 сен.
Андрей Чобану
11.7k2020 золотых знаков7676 серебряных знаков115115 бронзовых знаков
3
- Objective-C — это не C — это другой язык.
- C не является объектно-ориентированным языком. Можно делать что-то в стиле объектно-ориентированного программирования, но это не то, для чего он создан.
- Лучшие практики в C являются процедурными.
Создан 23 сен.
Skilldrick
65.7k3333 золотых знака169169 серебряных знаков226226 бронзовых знаков
4
Я бы порекомендовал изучить внутреннюю часть инструментария GTK + GUI. Это объектно-ориентированная система, написанная на C, демонстрирующая методы, которые вам нужны. Это открытый исходный код, поэтому ничто не мешает вам читать и учиться.
Создан 23 сен.
расслабиться
368k6161 золотой знак
0
Объектно-ориентированные механизмы не определены как функции языка C.Вам придется имитировать объектную ориентацию, добавив свою собственную логику поверх процедурной природы C.
.
Я бы не рекомендовал применять все аспекты ООП в C. Хотя инкапсуляцию относительно легко достичь, реализация наследования была бы действительно некрасивой на языке, который не был создан для этого.
Хорошее руководство по этому поводу: http://www.planetpdf.com/codecuts/pdfs/ooc.pdf
Создан 23 сен.
Благовест Буюклиев
39.9k1212 золотых знаков8888 серебряных знаков124124 бронзовых знака
Не тот ответ, который вы ищете? Посмотрите другие вопросы с метками c oop c89 или задайте свой вопрос.
язык-c
Stack Overflow лучше всего работает с включенным JavaScript
Ваша конфиденциальность
Нажимая «Принять все файлы cookie», вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Принимать все файлы cookie
Настроить параметры
Для C / C ++, когда лучше не использовать объектно-ориентированное программирование?
Ну, есть несколько альтернатив.Код не-ООП в C ++ вместо этого может быть:
- процедурный код в стиле C или
- Общее программирование в стиле C ++
Единственные преимущества первого — простота и обратная совместимость. Если вы пишете небольшое тривиальное приложение, то возиться с классами — пустая трата времени. Если вы пытаетесь написать «Hello World», просто позвоните уже по телефону printf
. Не беспокойтесь обернуть это в класс. И если вы работаете с существующей кодовой базой C, она, вероятно, не объектно-ориентирована, и попытки заставить ее перейти в другую парадигму, чем она уже используется, — это всего лишь рецепт боли.
Для последнего ситуация иная, поскольку этот подход часто превосходит «традиционный ООП».
Общее программирование дает вам большую производительность (среди прочего, потому что вы часто избегаете накладных расходов на vtables и потому что с меньшим косвенным обращением компилятор лучше может встроить), лучшую безопасность типов (потому что точный тип известен, а не скрывает его за интерфейсом), а также часто более чистый и лаконичный код (итераторы и алгоритмы STL позволяют многое из этого, без использования единственного экземпляра полиморфизма времени выполнения или виртуальных функций.
ООП — это не более чем устаревшее модное слово. Методология, которую все неправильно поняли (версия, поддерживаемая C ++ и Java, имеет мало общего с тем, что изначально означало ООП, как в SmallTalk), а затем притворились святым Граалем. Конечно, в нем есть полезные аспекты, но зачастую это не лучший подход для разработки приложения.
Скорее выразите общую логику другими средствами, например универсальным программированием, и , когда вам нужен класс для инкапсуляции некоторой простой концепции, обязательно спроектируйте его в соответствии с принципами ООП.
ООП — это просто инструмент среди многих. Цель состоит не в написании кода ООП, а в написании хорошего кода . Иногда для этого можно использовать принципы ООП, но часто можно улучшить код, используя общие принципы программирования или функциональное программирование.
% PDF-1.3
%
1601 0 объект
>
эндобдж
xref
1601 77
0000000016 00000 н.
0000001895 00000 н.
0000007991 00000 н.
0000008238 00000 п.
0000008325 00000 н.
0000008475 00000 н.
0000008538 00000 н.
0000008628 00000 н.
0000008723 00000 н.
0000008785 00000 н.
0000008892 00000 н.
0000008954 00000 н.
0000009075 00000 н.
0000009137 00000 п.
0000009262 00000 н.
0000009324 00000 п.
0000009445 00000 н.
0000009507 00000 н.
0000009619 00000 н.
0000009681 00000 п.
0000009801 00000 п.
0000009863 00000 н.
0000009978 00000 н.
0000010040 00000 п.
0000010151 00000 п.
0000010213 00000 п.
0000010333 00000 п.
0000010395 00000 п.
0000010517 00000 п.
0000010579 00000 п.
0000010700 00000 п.
0000010762 00000 п.
0000010878 00000 п.
0000010940 00000 п.
0000011058 00000 п.
0000011170 00000 п.
0000011232 00000 п.
0000011294 00000 п.
0000011412 00000 п.
0000011528 00000 п.
0000011589 00000 п.
0000011650 00000 п.
0000011780 00000 п.
0000011887 00000 п.
0000011948 00000 п.
0000012008 00000 п.
0000012071 00000 п.
0000012206 00000 п.
0000012466 00000 п.
0000013172 00000 п.
0000013650 00000 п.
0000014445 00000 п.
0000014468 00000 п.
0000015163 00000 п.
0000015186 00000 п.
0000015999 00000 н.
0000016022 00000 п.
0000016809 00000 п.
0000016832 00000 п.
0000017593 00000 п.
0000017616 00000 п.
0000018397 00000 п.
0000018420 00000 п.
0000019224 00000 п.
0000019512 00000 п.
0000020278 00000 н.
0000020301 00000 п.
0000021041 00000 п.
0000021064 00000 п.
0000021748 00000 п.
0000021868 00000 п.
0000025513 00000 п.
0000026371 00000 п.
0000027880 00000 п.
0000028306 00000 п.
0000001998 00000 н.
0000007967 00000 н.
трейлер
]
>>
startxref
0
%% EOF
1602 0 объект
>
эндобдж
1676 0 объект
>
ручей
H {4huI.q $ Ң̑uILqWDKҝ% K $ v ڸ T2 * vZ: MwGMwfϞ = g3_y |;
Объектно-ориентированное программирование на C ++
СОДЕРЖАНИЕ :
- Введение
- Класс
- Объекты
- Инкапсуляция
- Абстракция
- Полиморфизм
- Наследование
- 59 Передача сообщений 9002
Объектно-ориентированное программирование — как следует из названия, в программировании используются объекты. Объектно-ориентированное программирование направлено на реализацию реальных сущностей, таких как наследование, скрытие, полиморфизм и т. Д. В программировании.Основная цель ООП — связать вместе данные и функции, которые с ними работают, чтобы никакая другая часть кода не могла получить доступ к этим данным, кроме этой функции.
Характеристики языка объектно-ориентированного программирования
Класс : Строительный блок C ++, который ведет к объектно-ориентированному программированию, — это класс. Это определяемый пользователем тип данных, который содержит свои собственные элементы данных и функции-члены, к которым можно получить доступ и использовать, создав экземпляр этого класса.Класс подобен проекту объекта.
Например: рассмотрим класс автомобилей. Может быть много автомобилей с разными названиями и марками, но все они будут иметь некоторые общие свойства, например, все они будут иметь 4 колеса, ограничение скорости, диапазон пробега и т. Д. Итак, здесь Car — это класс, а колеса, ограничения скорости, пробег — это их свойства.
- Класс — это определяемый пользователем тип данных, который имеет элементы данных и функции-члены.
- Элементы данных — это переменные данных, а функции-члены — это функции, используемые для управления этими переменными, и вместе эти элементы данных и функции-члены определяют свойства и поведение объектов в классе.
- В приведенном выше примере класса Car элементом данных будет ограничение скорости, пробег и т. Д., А функции-члены могут применять тормоза, увеличивать скорость и т. Д.
Мы можем сказать, что класс в C ++ — это чертеж, представляющий группа объектов, обладающих некоторыми общими свойствами и поведением.
Объект: Объект — это идентифицируемый объект с некоторыми характеристиками и поведением. Объект — это экземпляр класса. Когда класс определен, память не выделяется, но когда он создается (т.е.е. объект создан) выделяется память.
класс
человек
{
char
name [20];
внутр
id;
public
:
void
getdetails () {}
};
int
main ()
{
человек p1;
}
Объект занимает место в памяти и имеет связанный адрес, такой как запись в паскале, структура или объединение в C.
Когда программа выполняется, объекты взаимодействуют, отправляя сообщения друг другу.
Каждый объект содержит данные и код для управления данными. Объекты могут взаимодействовать без необходимости знать детали данных или кода друг друга, достаточно знать тип принятого сообщения и тип ответа, возвращаемого объектами.
Инкапсуляция : Обычно инкапсуляция определяется как объединение данных и информации в один блок. В объектно-ориентированном программировании инкапсуляция определяется как связывание данных и функций, которые ими управляют.
Рассмотрим реальный пример инкапсуляции. В компании есть разные разделы, такие как раздел счетов, финансовый раздел, раздел продаж и т. Д. Финансовый раздел обрабатывает все финансовые транзакции и хранит записи всех данных, связанных с финансами. Точно так же отдел продаж обрабатывает все операции, связанные с продажами, и ведет учет всех продаж. Теперь может возникнуть ситуация, когда чиновнику из финансового отдела по каким-то причинам понадобятся все данные о продажах за конкретный месяц.В этом случае ему не разрешен прямой доступ к данным раздела продаж. Сначала ему нужно будет связаться с другим сотрудником отдела продаж, а затем попросить его предоставить конкретные данные. Вот что такое инкапсуляция. Здесь данные отдела продаж и сотрудники, которые могут ими манипулировать, объединены под одним названием «отдел продаж».
Инкапсуляция в C ++
Инкапсуляция также приводит к абстракции данных или сокрытию . Поскольку использование инкапсуляции также скрывает данные.В приведенном выше примере данные любого раздела, такого как продажи, финансы или счета, скрыты от любого другого раздела.
Абстракция : Абстракция данных — одна из наиболее существенных и важных функций объектно-ориентированного программирования на C ++. Абстракция означает отображение только важной информации и скрытие деталей. Абстракция данных относится к предоставлению только важной информации о данных внешнему миру, скрывая фоновые детали или реализацию.
Рассмотрим пример из реальной жизни человека, управляющего автомобилем.Человек знает только, что нажатие на педаль акселератора увеличит скорость автомобиля или нажатие на педаль тормоза остановит машину, но он не знает, как на самом деле увеличивается скорость при нажатии на педаль акселератора, он не знает о внутреннем механизме автомобиля или внедрение в автомобиль акселератора, тормозов и т. д. Вот что такое абстракция.
- Абстракция с использованием классов : Мы можем реализовать абстракцию на C ++ с помощью классов. Класс помогает нам группировать элементы данных и функции-члены с помощью доступных спецификаторов доступа.Класс может решить, какой член данных будет виден внешнему миру, а какой нет.
- Абстракция в файлах заголовков : Еще одним типом абстракции в C ++ могут быть файлы заголовков. Например, рассмотрим метод pow (), присутствующий в заголовочном файле math.h. Всякий раз, когда нам нужно вычислить степень числа, мы просто вызываем функцию pow (), присутствующую в файле заголовка math.h, и передаем числа в качестве аргументов, не зная базового алгоритма, согласно которому функция фактически вычисляет мощность чисел. .
Полиморфизм: Слово полиморфизм означает наличие множества форм. Проще говоря, мы можем определить полиморфизм как способность сообщения отображаться в более чем одной форме.
Человек одновременно может иметь разные характеристики. Как мужчина одновременно — это отец, муж, служащий. Итак, один и тот же человек ведет себя по-разному в разных ситуациях. Это называется полиморфизмом.
В разных случаях операция может вести себя по-разному.Поведение зависит от типов данных, используемых в операции.
C ++ поддерживает перегрузку операторов и функций.
- Перегрузка оператора : Процесс, при котором оператор демонстрирует различное поведение в разных случаях, известен как перегрузка оператора.
- Перегрузка функции : Перегрузка функции использует одно имя функции для выполнения различных типов задач.
Полиморфизм широко используется при реализации наследования.Пример : Предположим, нам нужно написать функцию для сложения некоторых целых чисел, иногда бывает 2 целых числа, иногда 3 целых числа. Мы можем написать метод сложения с тем же именем и разными параметрами, соответствующий метод будет вызываться в соответствии с параметрами.
Наследование : способность класса извлекать свойства и характеристики из другого класса называется наследованием. Наследование — одна из важнейших функций объектно-ориентированного программирования.
- Подкласс : Класс, наследующий свойства от другого класса, называется подклассом или производным классом.
- Суперкласс : Класс, свойства которого наследуются подклассом, называется базовым классом или суперклассом.
- Возможность повторного использования : Наследование поддерживает концепцию «повторного использования», т.е. когда мы хотим создать новый класс и уже есть класс, который включает в себя часть кода, который нам нужен, мы можем получить наш новый класс из существующего класса. .Делая это, мы повторно используем поля и методы существующего класса.
Пример : Собака, кошка, корова могут быть производным классом от базового класса животных.
Динамическое связывание: При динамическом связывании код, который должен быть выполнен в ответ на вызов функции, определяется во время выполнения. В C ++ есть виртуальные функции для поддержки этого.
Передача сообщений: Объекты взаимодействуют друг с другом, отправляя и получая информацию друг другу.Сообщение для объекта — это запрос на выполнение процедуры, и поэтому он вызывает функцию в принимающем объекте, которая генерирует желаемые результаты. Передача сообщений включает в себя указание имени объекта, имени функции и информации, которая будет отправлена.
Статьи по теме :
Эта статья предоставлена Ванкаяла Карунакар . Пожалуйста, напишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по теме, обсужденной выше.
% PDF-1.3
%
1601 0 объект
>
эндобдж
xref
1601 77
0000000016 00000 н.
0000001895 00000 н.
0000007991 00000 н.
0000008238 00000 п.
0000008325 00000 н.
0000008475 00000 н.
0000008538 00000 н.
0000008628 00000 н.
0000008723 00000 н.
0000008785 00000 н.
0000008892 00000 н.
0000008954 00000 н.
0000009075 00000 н.
0000009137 00000 п.
0000009262 00000 н.
0000009324 00000 п.
0000009445 00000 н.
0000009507 00000 н.
0000009619 00000 н.
0000009681 00000 п.
0000009801 00000 п.
0000009863 00000 н.
0000009978 00000 н.
0000010040 00000 п.
0000010151 00000 п.
0000010213 00000 п.
0000010333 00000 п.
0000010395 00000 п.
0000010517 00000 п.
0000010579 00000 п.
0000010700 00000 п.
0000010762 00000 п.
0000010878 00000 п.
0000010940 00000 п.
0000011058 00000 п.
0000011170 00000 п.
0000011232 00000 п.
0000011294 00000 п.
0000011412 00000 п.
0000011528 00000 п.
0000011589 00000 п.
0000011650 00000 п.
0000011780 00000 п.
0000011887 00000 п.
0000011948 00000 п.
0000012008 00000 п.
0000012071 00000 п.
0000012206 00000 п.
0000012466 00000 п.
0000013172 00000 п.
0000013650 00000 п.
0000014445 00000 п.
0000014468 00000 п.
0000015163 00000 п.
0000015186 00000 п.
0000015999 00000 н.
0000016022 00000 п.
0000016809 00000 п.
0000016832 00000 п.
0000017593 00000 п.
0000017616 00000 п.
0000018397 00000 п.
0000018420 00000 п.
0000019224 00000 п.
0000019512 00000 п.
0000020278 00000 н.
0000020301 00000 п.
0000021041 00000 п.
0000021064 00000 п.
0000021748 00000 п.
0000021868 00000 п.
0000025513 00000 п.
0000026371 00000 п.
0000027880 00000 п.
0000028306 00000 п.
0000001998 00000 н.
0000007967 00000 н.
трейлер
]
>>
startxref
0
%% EOF1602 0 объект
>
эндобдж
1676 0 объект
>
ручей
H {4huI.q $ Ң̑uILqWDKҝ% K $ v ڸ T2 * vZ: MwGMwfϞ = g3_y |;Объектно-ориентированные методы на C [Дмитрий Франк]
Хотя методы, описанные ниже, не будут очень популярны в наши дни (в конце концов, зачем вообще использовать C, если мы собираемся писать объектно-ориентированный код?), Они по-прежнему актуальны для встроенных систем и других низкоуровневых вещей (ядро разработка и т. д.). Например, многие подсистемы ядра Linux используют аналогичный подход.
Я много работаю со встроенными вещами: то есть у меня есть микроконтроллер с ограниченными ресурсами и ограниченным набором инструментальных средств, которые я могу использовать.Обычно это просто компилятор C, предоставляемый производителем микросхемы.
У меня также есть опыт работы с современными технологиями, такими как Java и Qt, и я думаю объектно-ориентированным способом. Не поймите меня неправильно, я не считаю это «единственно правильным способом» реализовать все: как всегда, мы должны руководствоваться здравым смыслом. Тем не менее, это достойный инструмент, который во многих случаях может пригодиться для создания модульного программного обеспечения, если мы используем его правильно.
Итак, конечно, я действительно хочу использовать объектно-ориентированный подход во встроенном мире, когда это уместно, и методы, о которых я собираюсь вам рассказать, сработали для меня довольно хорошо.В качестве примера, вот диаграмма классов (, нарисованная PlantUML ) подсистемы моего фактического встроенного проекта на C (конечно, кликабельна):
Он довольно большой. Полученная система работает стабильно и достаточно гибкая. Я понятия не имею, как бы реализовать все это с такой же степенью гибкости без объектно-ориентированного подхода.
Существуют компиляторы C ++ для , некоторые встроенные процессоры , но они необычны, поэтому мне нужно придерживаться C во имя переносимости.
Публикации по этой теме уже есть (например, см. Эту очень обстоятельную книгу), но ни одно из существующих решений меня не устраивает. Требования, которые у меня есть:
По возможности избегайте приведений типов, чтобы не потерять безопасность типов;
Полиморфизм: мы должны иметь возможность использовать виртуальные методы, а клиент класса не должен знать, является ли какой-то конкретный метод виртуальным или нет;
Множественное наследование: я не использую его часто, но иногда мне действительно нужно, чтобы какой-то класс реализовал несколько интерфейсов (или расширил несколько суперклассов).
Большинство существующих решений сильно используют приведение типов, поэтому мы теряем безопасность типов: компилятор не поможет вам, если вы сделаете ошибку. Это совершенно недопустимо.
Вот и решил поделиться своим опытом. Конечно, он не будет слишком гладким, но он надежен и архитектурно чист, поэтому он очень помогает мне в моей повседневной жизни программирования.
Использовать это или нет — предмет споров (если не священная война), и я не ожидаю, что все согласятся со мной.Для меня эмпирическое правило: не злоупотребляйте им. Если вам нужно разработать автомобильную мультимедийную систему, гораздо лучше получить более дорогой чип, который может работать под Linux, а затем написать приложение на C ++, которое будет работать в пользовательском пространстве. Но если это довольно небольшой проект на двухдолларовом MCU, это может быть подходящим вариантом. Применяйте здравый смысл.
Класс бетона
Обратите внимание, что вещи, которые я собираюсь рассказать вам в этом разделе, довольно тривиальны, если вы знакомы с основными техниками объектно-ориентированного программирования.
Начнем с очень простого, но реалистичного примера: калькулятора CRC. Фактически, это был мой первый опыт использования объектно-ориентированного программирования на языке Си много лет назад. В то время я работал над обновлением прошивки для устройства через Bluetooth, поэтому я хотел иметь какой-то общий модуль C, который я мог бы использовать на обеих сторонах (устройстве и главном компьютере).
Обычный подход C для вычисления таких вещей, как CRC, заключается в наличии однофункционального модуля, который вычисляет CRC буфера. Прототип функции выглядит так:
uint32_t crc32_calc (const uint8_t * buf, size_t size);Эта функция может работать на стороне хоста, где у нас много оперативной памяти.Однако такая функция не слишком полезна, если у нас нет всего буфера сразу. После завершения обновления прошивки загрузчик устройства должен сравнить вычисленную CRC запрограммированных данных с полученной от хоста. Если они совпадают, операция считается успешной. Даже если бы я хотел вычислить CRC «сразу», вызвав
crc32_calc ()
, я бы не смог, потому что флеш-пространство на MCU, с которым я работал, нелегко сопоставить с адресным пространством, и, конечно, MCU недостаточно RAM, чтобы я мог прочитать всю прошивку в RAM, а затем вычислить CRC.Вместо этого я хотел бы иметь возможность вычислять CRC постепенно: когда следующий кадр (скажем, 64 байта) получен от хоста, устройство программирует его для прошивки, затем считывает его обратно и накапливает («передает») эти данные в «Глобальный» CRC. Когда получен следующий кадр, он снова передается в глобальную CRC и так далее. В итоге у нас есть CRC всей прошивки.
Для этого на помощь приходит объектно-ориентированный подход. Нам нужен объект
Crc
, который имеет два метода:Поскольку C не поддерживает объектно-ориентированное программирование, мы должны вручную передать указатель на объект, для которого вызывается метод.Чтобы избежать бесполезной путаницы, я использую имя
me
вместоthis
.Вот самый простой интерфейс для этого:
- crc32.h
/ ********************************************** ******************************** * Калькулятор CRC32 ************************************************* **************************** / #ifndef _CRC32_H #define _CRC32_H / *********************************************** ****************************** * ВКЛЮЧЕННЫЕ ФАЙЛЫ ************************************************* **************************** / # включить/ *********************************************** ****************************** * ОБЩЕСТВЕННЫЕ ТИПЫ ************************************************* **************************** / / ** * Контекст объекта CRC32. * * Фактически, мы могли бы даже поместить его в исходный файл вместо файла заголовка, * но тогда мы можем выделить его только в куче, что может быть не очень хорошей идеей, * особенно во встроенном мире. * / struct S_Crc32 { uint32_t crc; }; / *********************************************** ****************************** * КОНСТРУКТОР, ДЕСТРУКТОР ************************************************* **************************** / void crc32_ctor (struct S_Crc32 * me); void crc32_dtor (struct S_Crc32 * me); / *********************************************** ****************************** * ПРОТОТИПЫ ПУБЛИЧНЫХ МЕТОДОВ ************************************************* **************************** / / ** * Передать следующий байт в crc32 * / void crc32_byte_feed (struct S_Crc32 * me, uint8_t byte); / ** * Получить текущее значение crc32 * / uint32_t crc32_value_get (const struct S_Crc32 * me); / *********************************************** ****************************** * конец файла ************************************************* **************************** / #endif / * _CRC32_H * / Реализация также довольно проста:
- crc32.в
/ ********************************************** ******************************** * ВКЛЮЧЕННЫЕ ФАЙЛЫ ************************************************* **************************** / #include "crc32.h" / *********************************************** ****************************** * КОНСТРУКТОР, ДЕСТРУКТОР ************************************************* **************************** / void crc32_ctor (struct S_Crc32 * me) { мне-> crc = 0xffffffff; } void crc32_dtor (struct S_Crc32 * me) { //-- здесь нечего делать } / *********************************************** ****************************** * ОБЩЕСТВЕННЫЕ МЕТОДЫ ************************************************* **************************** / / ** * Передать следующий байт в crc32 * / void crc32_byte_feed (struct S_Crc32 * me, uint8_t byte) { static const uint32_t _crc32_table [16] = { 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, }; me-> crc ^ = байт; me-> crc = _crc32_table [me-> crc & 0x0f] ^ (me-> crc >> 4); me-> crc = _crc32_table [me-> crc & 0x0f] ^ (me-> crc >> 4); } / ** * Получить текущее значение crc32 * / uint32_t crc32_value_get (const struct S_Crc32 * me) { верни меня-> crc ^ 0xffffffff; }Теперь мы можем использовать объект калькулятора crc32 следующим образом:
- основной.в
#include "crc32.h" #includeint main (пусто) { // - Выделить объект crc_calc и построить его struct S_Crc32 crc_calc; crc32_ctor (& crc_calc); // - Получаем байты откуда угодно и скармливаем их crc_calc // (в этом примере байты жестко запрограммированы) crc32_byte_feed (& crc_calc, 0x01); crc32_byte_feed (& crc_calc, 0x02); crc32_byte_feed (& crc_calc, 0x03); crc32_byte_feed (& crc_calc, 0x04); // - получаем значение crc32 uint32_t crc_val = crc32_value_get (& crc_calc); // - уничтожить crc_calc crc32_dtor (& crc_calc); } Отлично, это именно то, что нам нужно: мы можем получать данные откуда угодно и побайтно передавать данные в калькулятор CRC.
Кстати, модуль для создания снимков экрана в формате BMP, Bmp writer, использует аналогичный подход, поэтому вы можете также проверить его API .
А теперь перейдем к более интересному.
Наследование и полиморфизм
Я использую наследование, когда хочу, чтобы некоторые объекты имели общий интерфейс.
Подход, который я использую в C, довольно хорошо предлагает одноуровневое наследование, но поддержание иерархии большего количества уровней становится слишком многословным.К счастью, одноуровневого наследования обычно вполне достаточно для реализации общего интерфейса, который используется несколькими объектами, поэтому для меня это не является большой проблемой. Однако иногда я использую больше уровней, когда мне это действительно нужно. Единственная проблема в том, что он становится слишком многословным.
Когда некоторый класс (
Derived
) является производным от другого класса (Base
), тогда, с точки зрения C,struct Derived
содержитstruct Base
. Нравится:/ * базовый класс * / typedef struct S_Base { / *... * / } T_Base; / * производный класс * / typedef struct S_Derived { / * ... * / База T_Base; / * ... * / } T_DerivedЧтобы добиться полиморфизма, нам нужно вручную сделать то, что компилятор C ++ делает за кулисами: поддерживать таблицу виртуальных функций. Для каждого класса (но не для каждого экземпляра класса ) у нас будет структура с указателями на виртуальные функции.
По крайней мере, следующие предметы должны быть виртуальными:
деструктор
освободитель памяти
Виртуальный деструктор — довольно распространенная вещь: когда мы разрушаем экземпляр подкласса, то сначала должен быть вызван деструктор производного класса, а затем должен быть вызван деструктор базового класса.Нам также нужен освободитель виртуальной памяти, поскольку указатель на производный класс может не совпадать с указателем на базовый класс.
Я продолжу и скажу вам, что я подготовил небольшой инструмент, который генерирует для вас шаблонный код «класса», чтобы вам не приходилось самостоятельно набирать все следующие вещи. Вот он: https://github.com/dimonomid/ooc. В конце этой статьи я более подробно объясню его использование.
Базовый класс
Предположим, у нас есть базовый класс
MyBase
, который будет иметь несколько производных классов.Помимо деструктора и освобождения памяти, он имеет два виртуальных метода:some_method (int a, int b)
иother_method (void)
. Нам нужно определить прототипы для всех виртуальных методов:/ ********************************************** ******************************* * VTABLE ************************************************* **************************** / / ** * Деструктор * / typedef void (T_MyBase_Dtor) (T_MyBase * me); / ** * Освободитель памяти.Необходимо переопределить, потому что указатель на подкласс не * обязательно соответствует указателю на суперкласс. * / typedef void (T_MyBase_Free) (T_MyBase * me); / ** * Какой-то метод * / typedef void (T_MyBase_SomeMethod) (T_MyBase * me, int a, int b); / ** * Другой метод * / typedef void (T_MyBase_OtherMethod) (T_MyBase * me);Обратите внимание, что каждый из них явно принимает указатель на объект, для которого вызывается метод. Теперь создайте таблицу виртуальных функций (vtable):
/ ** * Таблица виртуальных функций (vtable) * / typedef struct S_MyBase_VTable { T_MyBase_Dtor * p_dtor; T_MyBase_Free * p_free; T_MyBase_SomeMethod * p_some_method; T_MyBase_OtherMethod * p_other_method; } T_MyBase_VTable;И контекст объекта
MyBase
должен содержать указатель на эту vtable:struct S_MyBase { / *... * / struct S_MyBase_VTable * p_vtable; / * ... * / };Очевидно, мы должны реализовать эти виртуальные методы для
MyBase
:static void _some_method (T_MyBase * me, int a, int b) { / * ... * / } static void _other_method (T_MyBase * me) { / * ... * / } статическая пустота _dtor (T_MyBase * me) { / * ... * / } статическая пустота _free (T_MyBase * me) { освободи меня); }Теперь вопрос: как инициализировать vtable. Первым делом я решил сделать
const
, вот так:/ * не очень хорошо: * / static const T_MyBase_VTable _vtable = { .p_dtor = _dtor, .p_free = _free, .p_some_method = _some_method, .p_other_method = _other_method, };Этот подход работает, но у него есть серьезный недостаток для производных классов: когда мы определяем vtable для производного класса, мы можем или не можем захотеть переопределить какой-то конкретный метод. Если мы это сделаем, это не проблема: мы просто указываем указатель на функцию, которая переопределяет указатель из базового класса. Но если нет, то:
Нам нужно каким-то образом получить указатель на базовую функцию.Таким образом, эти функции больше не могут быть
static
, и все подклассы должны иметь к ним доступ;Когда мы добавляем новый виртуальный метод в vtable, нам нужно вручную изменить vtable всех подклассов. Эта практика подвержена ошибкам;
Это нарушает принцип DRY (Don’t Repeat Yourself).
После некоторого исследования я решил сделать его неконстантным и использовать ленивую инициализацию. Этот подход работал у меня годами, и я вполне им доволен.Итак, для
MyBase
у нас будет vtable и переменнаяbool
, указывающая состояние vtable (инициализировано или нет):статический T_MyBase_VTable _vtable; статический bool _bool_vtable_initialized = 0;Нам нужна функция, которая при необходимости инициализирует vtable:
static void _vtable_init () { if (! _bool_vtable_initialized) { _vtable.p_dtor = _dtor; _vtable.p_free = _free; _vtable.p_some_method = _some_method; _vtable.p_other_method = _other_method; _bool_vtable_initialized = true; } }И, наконец, эту функцию нужно вызвать из конструктора. Итак, когда создается первый экземпляр класса
MyBase
, его vtable инициализируется. Когда создается больше экземпляров, vtable больше не изменяется.Переходим к конструктору. Конструктору обычно нужны параметры. Лично я считаю полезным создать специальную структуру для параметров конструктора и реализовать конструктор, чтобы он принимал указатель на эту структуру.Таким образом, мы можем легко добавить новые параметры в ctor позже, и нам не нужно для этого изменять сигнатуры функций. Итак, изначально структура params пуста:
typedef struct S_MyBase_CtorParams { // - добавьте сюда параметры вашего ctor } T_MyBase_CtorParams;А конструктор может выглядеть так:
/ ** * Конструктор * / void mybase__ctor (T_MyBase * me, const T_MyBase_CtorParams * p_params) { memset (меня, 0x00, sizeof (T_MyBase)); // - init vtable _vtable_init (); я-> p_vtable = & _vtable; // - код конструкции }Теперь мы можем легко определять не виртуальные методы:
недействителен mybase__my_method (T_MyBase * me) { / *... * / }Но как мы будем вызывать виртуальные методы? Мы определенно не хотим возлагать бремя работы с vtable на клиента
MyBase
. Итак, для каждого виртуального метода (кроме освобождения памяти) мы просто определяем встроенную функцию в заголовке:/ ** * Desctructor * / статический встроенный void mybase__dtor (T_MyBase * me) { я-> p_vtable-> p_dtor (я); } / ** * Какой-то метод * / статический встроенный void mybase__some_method (T_MyBase * me, int a, int b) { me-> p_vtable-> p_some_method (мне, а, б); } / ** * Другой метод * / статический встроенный void mybase__other_method (T_MyBase * me) { я-> p_vtable-> p_other_method (я); }Теперь клиент
MyBase
может в равной степени вызыватьmybase__some_method ()
илиmybase__other_method ()
, и ему / ей не нужно заботиться о том, является ли метод виртуальным или нет.Если нам нужно использовать кучу, нам также необходимо определить распределитель (который также будет вызывать конструктор) и освободитель (который будет вызывать деструктор). Я предпочитаю называть их так, чтобы воспроизвести операторы
new
иdelete
из C ++:/ * распределитель * / T_MyBase * new_mybase (const T_MyBase_CtorParams * p_params) { T_MyBase * me = (T_MyBase *) malloc (sizeof (T_MyBase)); mybase__ctor (я, p_params); верни меня; } / * освободитель * / void delete_mybase (T_MyBase * me) { mybase__dtor (я); я-> p_vtable-> p_free (я); }Теперь мы можем использовать наш класс следующим образом:
T_MyBase_CtorParams params = {}; // - в стеке { T_MyBase mybase; mybase__ctor (& mybase, & params); mybase__some_method (& mybase, 1, 2); mybase__dtor (& mybase); } // - в куче { T_MyBase * p_mybase = new_mybase (& params); mybase__some_method (p_mybase, 1, 2); delete_mybase (p_mybase); }Итак, если мы создадим два экземпляра
T_MyBase
:my_base_1
иmy_base_2
, данные и код будут расположены следующим образом:Обратите внимание, что даже несмотря на то, что мы переносим некоторые объекты в C, мы не можем писать на C так же, как в C ++: в C мы должны вручную вызывать
new_… ()
/delete_… ()
(или конструктор / деструктор), но в C ++ мы должны по возможности избегать простогоdelete
и вместо этого полагаться на RAII.Хорошо, базовый класс, кажется, выполнен в первом приближении, давайте теперь перейдем к производному классу.
Производный класс
Как я уже упоминал, я использую наследование, когда хочу, чтобы некоторые объекты разделяли
Общий интерфейс. Итак, интерфейс уже готов (для базового класса), теперь мы
должен сделать производный класс доступным через этот интерфейс.Прежде всего, определим структуру контекста производного класса:
struct S_MyDerived { / * ... * / struct { T_MyBase mybase; } супер; / * ... * / };Я хотел бы поместить базовые классы в отдельную структуру
super
, даже если она
более подробный. Если хотите, можете опустить его, а именно:struct S_MyDerived { / * ... * / T_MyBase mybase; / * ... * / };В остальной части текста я исхожу из первого подхода. Нам нужен способ конвертировать
между указателем на базовый класс и указателем на производный класс. В
производное-в-основание тривиально, и я бы поместил его в заголовок как статическую встроенную функцию:статический встроенный T_MyBase * mydehibited__mybase__get (T_MyDerived * me) { return & (me-> super.mybase); }Но для обратного преобразования нам нужно проделать некоторые ухищрения.
Во-первых, мы хотели бы убедиться, что данный указатель на базовый класс действительно
указывает на экземпляр некоторого конкретного производного класса. К сожалению, это
не так-то просто реализовать правильно без некоего RTTI (время выполнения
информация о типе). Я еще не беспокоился о RTTI в C. Но, как я уже
Как уже упоминалось, в большинстве случаев я доволен одноуровневым наследованием. А потом мы
есть очень простое решение: поскольку у производного класса есть собственная vtable, мы можем просто
проверьте, что указатель на vtable в данном экземпляре действительно указывает на vtable
некоторого конкретного подкласса:/ * * ПРИМЕЧАНИЕ: работает только для одноуровневой иерархии! * / bool instanceof_mydehibited (const T_MyBase * me_super) { // - здесь мы просто проверяем указатель на vtable.return (me_super-> p_vtable == & _super_vtable); }
_super_vtable
будет объяснено позже, но я уверен, что вы уже догадались
как это определяется.Во-вторых, мы не можем просто привести тип из
T_MyBase *
вT_MyDerived *
, поскольку
mybase
может быть не первым полемT_MyDerived
. По крайней мере, что
неизбежно происходит при множественном наследовании. Нам нужно быть умнее.Я создал файл заголовка
ooc.h
, в который я положил обычные вещи полезные
для объектно-ориентированного подхода в C. По крайней мере, есть пара макросов:/ ** * Вычисляет смещение члена внутри структуры * / #define OOC_OFFSETOF (_struct_, _member_) (size_t) & (((_ struct_ *) 0) -> _ member_) / ** * Вычисляет указатель на подкласс (т.е. содержащий структуру) от указателя на * суперкласс (т.е. содержащаяся структура). * / #define OOC_GET_CONTAINER_PT (\ _T_Подкласс_, \ _superclass_field_name_, \ _superclass_pt_ \ ) \ \ ((_T_Подкласс_ *) (\ (символ без знака *) (_ суперкласс_pt_) \ - OOC_OFFSETOF (_T_Subclass_, _superclass_field_name_) \ ) \ )Учитывая макрос
OOC_GET_CONTAINER_PT ()
, мы можем вычислить смещение базового класса
поле в структуре производного класса.В начале этой статьи я упомянул, что хочу избежать приведения типов
как можно больше, но в макросе выше вы четко видите приведение типов к
подкласс. Это единственное приведение типов, которое я использую в своем подходе OOC, и это
локализован в четко определенный макрос, чтобы мы не ошиблись
здесь. Более того, код, использующий этот макрос, автоматически создается из шаблона.
(см. https://github.com/dimonomid/ooc), поэтому вы не
приходиться писать его вручную для каждого нового подкласса. Я считаю это вполне
приемлемо (с учетом того, что другого способа конвертировать из
от базы к производной).Итак, преобразование базы в производную будет выполнено следующим образом:
T_MyDerived * mydehibited__get_by_mybase (const T_MyBase * me_super) { T_MyDerived * p_dehibited = NULL; if (instanceof_mydehibited (me_super)) { p_dehibited = OOC_GET_CONTAINER_PT ( T_MyDerived, super.mybase, me_super ); } еще { // - TODO: возможно, добавить некоторую ошибку времени выполнения } вернуть p_dehibited; }Перейдем к реализации виртуальных методов для производного класса.Производные
классу нужен доступ к vtable базового класса. Итак, мы должны добавить функцию в
базовый класс для этого:const T_MyBase_VTable * _mybase__vtable__get (недействительно) { _vtable_init (); вернуть & _vtable; }Эта функция считается «защищенной», т.е. ожидается, что она будет вызываться только из подклассов. Я счел полезным добавить префикс подчеркивания к «защищенным» функциям.
Теперь подкласс может вызвать
_mybase__vtable__get
, чтобы получить указатель на vtable базового класса.Реализуем виртуальные методы:static void _some_method (T_MyBase * me_super, int a, int b) { // - вызов метода суперкласса (если нам тоже нужно наследование реализации) _mybase__vtable__get () -> p_some_method (me_super, a, b); T_MyDerived * me = mydehibited__get_by_mybase (me_super); / * ... * / } / ** * Деструктор (виртуальный) * / статическая пустота _dtor (T_MyBase * me_super) { T_MyDerived * me = mydehibited__get_by_mybase (me_super); / * ... какой-то деструктивный код ... * / // ПРИМЕЧАНИЕ: это подкласс, поэтому после выполнения кода уничтожения // мы должны вызвать деструктор суперкласса: _mybase__vtable__get () -> p_dtor (me_super); } / ** * Освободитель памяти (виртуальный) * / статическая пустота _free (T_MyBase * me_super) { // - нам нужно освободить указатель на «внешнюю» структуру, а не на «внутреннюю».T_MyDerived * me = mydehibited__get_by_mybase (me_super); освободи меня); }Как видите, в этих реализациях мы используем
mydehibited__get_by_mybase ()
сильно, поскольку эти функции принимают указатель на базовый класс, а не на
производный класс (см. выше прототипы виртуальных функций:T_MyBase_Dtor
,
так далее). Кроме того, при необходимости мы должны вызывать метод базового класса.
Скажем, в_dtor
это обязательно (потому что мы явно хотим, чтобы базовый класс
выполнить необходимую очистку), но в_some_method ()
мы, возможно, не захотим
наследовать реализацию, поэтому мы можем пропустить там вызов базового метода.Теперь нам нужно создать vtable для нашего производного класса. Вот:
статический T_MyBase_VTable _super_vtable; статический OOC_BOOL _bool_vtable_initialized = 0;И функция, которая его инициализирует, похожа на функцию базового класса, но
здесь мы сначала копируем vtable из базы, а затем переопределяем то, что хотим:static void _vtable_init () { if (! _bool_vtable_initialized) { // - во-первых, просто скопируем vtable базового класса _super_vtable = * _mybase__vtable__get (); // - а затем укажите, что нам нужно переопределить.// Неизбежно есть _dtor и _free. _super_vtable.p_dtor = _dtor; _super_vtable.p_free = _free; // - а затем наши собственные виртуальные методы. Если мы не переопределим их здесь, // все в порядке: тогда будут вызваны методы базового класса. _super_vtable.p_some_method = _some_method; // - помните, что vtable уже инициализирована. _bool_vtable_initialized = 1; } }Обратите внимание, что вполне нормально не переопределять какой-либо метод (кроме
_dtor
и_free
): вы могли заметить, что мы ушли
p_other_method
без изменений, поэтому он указывает на базовый класс.Мы не смогли бы достичь такого удобства, если бы vtable былаconst
.Переходим к конструктору сейчас. Для производного класса мы создаем собственную структуру с
params, который, конечно же, будет содержать структуру с базовыми параметрами:typedef struct S_MyDerived_CtorParams { T_MyBase_CtorParams super_params; // - добавьте сюда параметры вашего ctor } T_MyDerived_CtorParams;А конструктор выглядит следующим образом:
недействителен мойдеривед__ctor (T_MyDerived * me, const T_MyDerived_CtorParams * p_params) { memset (меня, 0x00, sizeof (T_MyDerived)); mybase__ctor (& я-> super.mybase, & p_params-> super_params); // - инициализация виртуальных методов _vtable_init (); me-> super.mybase.p_vtable = & _super_vtable; // - код конструкции }Мы почти закончили. Чего не хватает, так это распределителя для нашего производного класса:
T_MyDerived * new_mydehibited (const T_MyDerived_CtorParams * p_params) { T_MyDerived * me = (T_MyDerived *) malloc (sizeof (T_MyDerived)); мойдеривод__ctor (я, p_params); верни меня; }Обратите внимание, что нам не нужен деаллокатор: для этого деаллокатор базового класса
следует использовать (см. раздел «Использование» ниже).Итак, если мы создадим два экземпляра
T_MyBase
:my_base_1
иmy_base_2
,
и один экземплярT_MyDerived
:my_dehibited_1
, данные и код будут
быть устроен следующим образом:Некоторые выводы
Обратите внимание, что каждый экземпляр класса (базовый или производный) имеет указатель на vtable, а не на саму vtable.
В качестве примера представим, что у нас есть один базовый класс
Shape
и три производных класса:Circle
,Triangle
,Rectangle
.У нас, вероятно, будет много виртуальных методов для этих классов, для рисования, изменения размера, преобразования их и т. Д. И мы используем их в каком-то GUI — обширном приложении с множеством форм: пусть это будет 100Circle
s, 100Треугольник
s и 100Прямоугольник
s.С помощью методов, описанных в этой статье, мы получаем всего 4 vtables, а не 300 vtables, поскольку vtable создается для каждого класса, а не для каждого экземпляра . Фактически, это примерно то, что компилятор C ++ делает для вас за кулисами, когда вы используете виртуальные методы (ну, на самом деле компилятор C ++ может быть даже умнее: он может исключать указатели на непереопределенные методы, но поддержание этого вручную в C является вряд ли путь).
Таким образом, этот подход не тратит вашу оперативную память, чего всегда недостаточно во встроенном мире.
Использование
Существует очень важный принцип проектирования: « программирует интерфейс, а не
реализация ». Если вы не слышали об этом, вам, вероятно, следует прочитать
Дизайн
Книгу выкройки, или хотя бы
это
разговор с его автором.Собственно, именно поэтому я вообще потрудился реализовать все это: я
хочу, чтобы большая часть моего кода не заботилась о точных классах объектов, с которыми он
работает; вместо этого код должен работать с некоторыми общими интерфейсами.Скажем, у нас может быть какая-то функция, которая работает с базовым классом, а затем удаляет
Это:недействителен my_func (T_MyBase * p_base) { / * ... * / mybase__some_method (p_base, 1, 2); / * ... * / delete_mybase (p_base); }Затем мы можем в равной степени использовать для этого базовый или производный класс. Рассматривать:
int main (void) { // - использовать базовый класс { const T_MyBase_CtorParams params = {/ * ... * /}; T_MyBase * p_mybase = new_mybase (& params); my_func (p_mybase); } // - использовать производный класс { const T_MyDerived_CtorParams params = {/ *... * /}; T_MyDerived * p_mydehibited = new_mydehibited (& params); T_MyBase * p_mybase_inner = mydehibited__mybase__get (p_mydehibited); my_func (p_mybase_inner); } }В любом случае (с базовым или производным классом) все будет работать должным образом:
будет вызвана соответствующая версия some_method (), а когдаmy_func ()
удаляет объект, вызываются необходимые деструкторы и освобождается память
правильно. То естьmy_func ()
совершенно не знает точного типа
объект, с которым работает; он знает интерфейс.Конечно, мы можем написать его более компактно, но я хотел подробнее остановиться на
обрабатывать больше, поэтому я подробно написал.Обратите внимание, что когда мы вызываем
mybase__some_method ()
на экземпляреT_MyDerived
,
фактический указатель, данный на_some_method ()
производного класса, является указателем
в базовый класс, завернутый в производный. Вот почему он названme_super
.
А затем мы можем получить указатель на экземпляр, производный от оболочки, вызвав
мой производный__get_by_mybase (me_super)
.Рассмотрим эту цепочку вызовов, которая происходит, когда мы вызываем
my_func (p_mybase_inner)
:Конечно, компилятор оптимизирует вызов встроенного
mybase__some_method ()
, но идея все та же.Генератор кода модели
Написание всего этого беспорядка вручную для каждого нового класса или постоянное копирование из существующих классов было бы утомительным и подверженным ошибкам, поэтому я написал небольшую утилиту, которая генерирует шаблоны базовых и производных классов с заданными именами.
Вот он: https://github.com/dimonomid/ooc
Скрипт
ooc_gen.rb
написан на ruby, поэтому вам понадобится Ruby, чтобы он работал.Использование тривиально:
Сгенерируйте базовый класс
Shape
и подклассCircle
:$ ruby ooc_gen.rb круг новой формы классаСгенерируйте базовый класс
Shape
и два подкласса:Circle
иMyShape
:$ рубиновый ooc_gen.rb новый класс формы круга myshape: MyShapeПосле любой команды в текущем каталоге будет создан каталог
и форма
, содержащий все сгенерированные файлы.Таким образом, каждое имя класса может быть указано как одно слово в нижнем регистре (разделенное подчеркиванием) или как два слова, разделенных двоеточием.
Если камелизированная версия не предоставляется пользователем, она создается автоматически, что не всегда то, что вам нужно (скажем, для
myshape
автоматически созданная версия —Myshape
.Однако, если вы предоставитеmy_shape
, он будет преобразован вMyShape
).Чтобы использовать сгенерированные классы, вам также понадобятся
ooc.c
иooc.h
и файл конфигурацииooc_cfg.h
(сначала просто скопируйтеooc_cfg_default.h
какooc_cfg.h
в свой проект)Вас также могут заинтересовать:
Обсудить на Reddit: или в Hacker News:
Проголосовать на HNПожертвовать
Концепции объектно-ориентированного программирования C ++
Объектно-ориентированное программирование — это стиль программирования, связанный с концепцией класса, объектов и различными другими концепциями, вращающимися вокруг этих двух, таких как наследование, полиморфизм, абстракция, инкапсуляция и т. Д.
В видео ниже мы объяснили основные концепции объектно-ориентированного программирования с помощью очень простого для понимания примера. Если вы хотите пропустить видео, все это также описано ниже.
Попробуем немного разобраться во всем этом на простом примере. Человеческие существа — это живые формы, которые можно разделить на два типа: мужские и женские. Правильно? Это правда. У каждого Человека (мужчины или женщины) есть две ноги, две руки, два глаза, один нос, одно сердце и т. Д.Есть части тела, которые являются общими для мужчин и женщин, но есть некоторые специфические части тела, присутствующие у мужчин, которых нет у женщин, и некоторые части тела присутствуют у женщин, но не у мужчин.
Все Человеческие Существа ходят, едят, видят, разговаривают, слышат и т. Д. И снова, и Мужчина, и Женщина, выполняют некоторые общие функции, но у обоих есть некоторые особенности, которые не действительны для другого. Например: самка может рожать, а самец — нет, так что это только для самки.
Анатомия человека — это интересно, не правда ли? Но давайте посмотрим, как все это связано с C ++ и OOPS. Здесь мы попытаемся объяснить все концепции OOPS на этом примере, а позже у нас будут технические определения всего этого.
Класс
Здесь мы можем взять Человек как класс. Класс — это образец для любого функционального объекта, который определяет его свойства и функции. Как Человеческое Существо, имеющее части тела и совершающее различные действия.
Наследование
Учитывая, что
HumanBeing
— это класс, который имеет такие свойства, как руки, ноги, глаза и т. Д., И функции, такие как ходьба, разговор, еда, видение и т. Д.Male
иFemale
также являются классами, но большинство свойств и функций являются включены вHumanBeing
, поэтому они могут наследовать все от классаHumanBeing
, используя концепцию Inheritance .Объекты
Меня зовут Абхишек, я экземпляр / объект класса
Мужской
.Когда мы говорим «Человеческое Существо, Мужчина или Женщина», мы просто имеем в виду вид, ты, твой друг, я — формы этих классов. У нас есть физическое существование, в то время как класс — это всего лишь логическое определение. Мы объекты.Абстракция
Абстракция означает демонстрацию только необходимых вещей внешнему миру, скрывая при этом детали. Продолжая наш пример, Человеческое существо может говорить, ходить, слышать, есть, но детали скрыты от внешнего мира. В нашем случае мы можем использовать нашу кожу как фактор абстракции, скрывая внутренний механизм.
Инкапсуляция
Эту концепцию немного сложно объяснить на нашем примере. Наши ноги связаны, чтобы мы могли ходить. Наши руки помогают нам удерживать вещи. Эта привязка свойств к функциям называется инкапсуляцией.
Полиморфизм
Полиморфизм — это концепция, которая позволяет нам переопределить способ работы чего-либо, либо изменяя способ выполнения, либо изменяя части, с помощью которых это делается. Оба пути имеют разные термины.
Если мы будем ходить руками, а не ногами, здесь мы изменим части, которые используются для выполнения чего-либо. Следовательно, это называется Перегрузка .
И если есть определенный способ ходьбы, но я хочу ходить по-другому, но ногами, как все. Тогда я смогу ходить, как хочу, это будет называться Overriding .
Определения концепции OOPS
Теперь давайте обсудим некоторые из основных возможностей объектно-ориентированного программирования, которые вы будете использовать в C ++ (технически).
- Объектов
- Классы
- Абстракция
- Инкапсуляция
- Наследование
- Перегрузка
- Обработка исключений
Объекты
Объекты — основная единица ООП. Это экземпляры класса, которые имеют члены-данные и используют различные функции-члены для выполнения задач.
Класс
Это похоже на структуры в языке C. Класс также может быть определен как тип данных, определяемый пользователем, но он также содержит в себе функции.Итак, класс — это, по сути, план объекта. Он объявляет и определяет, какие переменные данных будет у объекта и какие операции могут быть выполнены с объектом класса.
Абстракция
Абстракция — это отображение только основных функций приложения и сокрытие деталей. В C ++ классы могут предоставлять методы для внешнего мира для доступа и использования переменных данных, сохраняя переменные скрытыми от прямого доступа, или классы могут даже объявлять все доступным для всех или, может быть, только для классов, наследующих это.Это можно сделать с помощью спецификаторов доступа.
Инкапсуляция
Еще можно сказать привязка данных. Инкапсуляция — это все о связывании переменных данных и функций вместе в классе.
Наследование
Наследование — это способ многократно использовать однажды написанный код снова и снова. Унаследованный класс называется Base class, а наследуемый класс называется Derived class. Их также называют родительским и дочерним классами.
Итак, когда производный класс наследует базовый класс, производный класс может использовать все функции, которые определены в базовом классе, что делает код пригодным для повторного использования.
Полиморфизм
Это функция, которая позволяет нам создавать функции с одинаковыми именами, но разными аргументами, которые будут выполнять разные действия. Это означает, что функции имеют одно и то же имя, но функционируют по-разному. Или это также позволяет нам переопределить функцию, чтобы дать ей совершенно новое определение.Вы узнаете, как это сделать, в ближайших уроках.
Обработка исключений
Обработка исключений — это функция ООП для обработки неразрешенных исключений или ошибок, возникающих во время выполнения.
.