Классы

C++ для начинающих. Раздельная компиляция (Продолжаем Знакомство)

В программировании С++, при использовании ООП, поощряется разделение класса на отдельные единицы. В понимании новичков, эти единицы — это файлы. Чтобы использовать один класс в большом числе случаев создают аж целых три файла. Я говорю "файлы", чтобы читателю было проще понять о чем идет речь. Каждый из этих файлов является кирпичиком функциональности класса.
1. Файл — файл интерфейса
2. Файл — файл реализации
3. Нечто — Это нечто обращается к элементам реализации.

Файл интерфейса — это заголовочный файл, который содержит описание класса. Это такое подобие прототипов функций, только получается что-то похожее на прототип класса. Согласно моей терминологии, внутри файла описывают прототип класса и ничего более.
Пример прототипа класса

Это очень схематично, если описать такой класс и создать для него объект, то программа успешно скомпилируется и запустится.

Это успешно компилируется и запускается. Единственное чего не хватает, это имя переменной для int, оно нужно для того, чтобы знать элемент, к которому в последующем будет обращение. Это всего-лишь вид «прототип-класса».(Это нестандартная терминология). Вот это описание и есть описание интерфейса класса. Только в правильном варианте оно выглядит так

  • Код С++ описание интерфейса класса
  • Вот, никаких int main(){} внутри интерфейса класса быть не должно. Функция main должна быть в третьей части, в части "Нечто, что использует класс"
    Под интерфейсом класса понимают такое описание класса, которое отображает суть класса. Ничего лишнего в этой части быть не должно. В текущем примере (где 5 строчек) легко увидеть всю суть класса и понять, в классе есть целочисленное значение и есть функция foo, которая возвращает что-то типа int и доступна из любых мест вне класса. Тут сейчас нет функции, есть только ее прототип, вот описание поведения функции, коей выписан прототип, выносят в отдельный файл. Все описания поведения функций для этого класса нужно записать в один отдельный файл. Файл с описанием поведений функций станет файлом реализации. Название файл-реализации как раз происходит из-за того что внутри такого файла описывают поведение функции или, можно сказать, реализовывают функции.

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

    • Файл интерфейса по некоторому соглашению сохраняют с расширением *.h
    • Файл реализации по некоторому соглашению сохраняют с расширением *.cpp

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

    То есть класс мог быть разделен на две составляющие с именами
    MyClass.h
    MyClass.cpp

    Здесь одинаковые имена MyClass, разные расширения.
    Программа, использующая подобный класс может называться как угодно, она абсолютно не зависит от класса. Она только нуждается в подключении класса при необходимости. Такую программу в некоторой литературе могут называть программой-драйвером (программа владеет классом и может использовать объекты класса и всю их функциональнось).

    Пришло время примеров. Не будем выдумать ничего неординарного. Создание классного журнала (журнал для школьных оценок). Я буду делать очень минималистическую функциональность в связи с большим объемом информации по теме.

    Требуется определится с функциональностью класса и что от него требуется. Для начала достаточно минимальной функциональности. Иначе сложно объяснить. Делаем небольшой анализ, продумываем класс:
    1. Журнал ведется по определенному предмету, значит класс должен
    — хранить название предмета
    — сохранять/устанавливать название предмета
    — должна быть возможность узнать название предмета

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

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

    Таким образом, сейчас должен иметься один сохраненный файл с описанием интерфейса класса.
    Следующий шаг — описание поведения функций. Создается еще один файл, с таким же именем, но другим расширением MyGradeBook.cpp, в котором пишут функции. В этом файле с помощью диррективы #include подключают интерфейс класса. Т.е. это выглядит так

    • Файл MyGradeBook.cpp

    Это нужно, чтобы файл реализации что-то знал о внешнем мире. Благодаря такому подключению, файл MyGradeBook.cpp знает о существовании класса class GradeBook, больше он пока что ничего не знает. В общем, это такой вид связи файлов. Так как файл MyGradeBook.cpp знает о существовании класса, то, в нем легко можно описать функции-члены класса. Вот их в нем и описывают.

    • Файл MyGradeBook.cpp

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

    • MyGradeBook.h

    • MyGradeBook.cpp

    Вот такой минипроект. Файл MyGradeBook.cpp должен успешно компилироваться. Если он не компилируется, значит где-то допущена ошибка. Например пропущена точка с запятой внутри файла-интерфейса после описание класса (распространенная ошибка). Проверили, если что-то надо исправить исправили и убрали отсюда main, здесь этой функции быть не должно. Функция main должна быть в программе, которая будет задействовать класс.

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

    • MyGradeBook.h

    • MyGradeBook.cpp

    Теперь готова полноценная программа, соответствующая концепции ООП. Есть класс, который можно использовать при написании какого-либо проекта.
    Временно забываем о существовании нашего класса. Делаем вид, что его писали не мы и что мы об этом классе сейчас ничего не знаем, кроме того что он существует и у него есть две возможности (установить значение, прочитать значение).

    Начинаем разработку какого-то кода. При работе в IDE, создаем проект. Обратите внимание на то, что, если Вы работаете не с командной строкой, а интегрированной средой разработки, то создается именно проект. Сейчас желательно пуcтой (empty) проект. В этот проект добавляются файлы реализации *.cpp, но не заголовочные файлы *.h. Добавление файлов в разных IDE может иметь различные вариации, но все сводится приблизительно к тому, что надо найти меню проекта, в меню проекта найти добавить файлы (add files…) и добавить все желаемые в проекте файлы реализации. К сожалению в разных IDE меню может различаться, а из-за этого нельзя единогласно рассказать как и где добавлять. В VS2015 фалы можно добавлять через обозреватель решений, в CodeBlocks через view-manager и т.д. Вам прийдется разбираться со своей IDE самостоятельно. Вернемся к проекту. В нашем случае в проект нужно добавить все *.cpp файлы. Таких файлов должно быть два. Первый файл — это файл реализации функций класса, второй файл — это то нечто, нечто что-то, что этот класс станет использовать.

    Предположительно Вы повозились с Вашей IDE и разузнали как создавать проект и добавлять в него файлы. Если да, то идем дальше.

    • MyGradeBook.h

    • MyGradeBook.cpp

    • Нечто, что в чем будет использован класс 12345.cpp

    Если все было сделано правильно, то попытка собрать 12345.cpp будет успешной и программа выполнится словно она была описана в одном файле. Только в VS может потребоваться задержка, чтобы консоль сразу не закрывалась. тогда Код может выглядеть так

    • Нечто, что в чем будет использован класс 12345.cpp

    Хочу обратить внимание на подключение заголовочных файлов. Тут разделения нет, что если подключен в одном файле, то сработает везде. Если в каком-то файле проекта требуется использовать что-то, что требует использования заголовочных файлов, то тогда надо подключать такой заголовочный файл непосредственно внутри нужного файла (реализация, интерфейс, нечто). Как пример, #include + cout описан у меня в разных местах. Просто требуется указывать такие вещи на месте.

    Внутри файла реализации можно описывать автономные функции, которые к классу не принадлежат. Такие функции не могут обращаться к закрытым элементам данных класса или вызывать элемент-функции класса, не специфицируя объект.

    • MyGradeBook.cpp

     
     

    Процесс компиляции и компоновки


    Часто бывает так, что интерфейс и реализация класса пишутся и компилируются одним программистом, а используются другим, который реализует код клиента класса.
    Программист класса, отвечающий за создание используемого класса GradeBook, пишет заголовочный файл MyGradeBook.h и файл исходного кода MyGradeBook.cpp, который включает директивой #include заголовочный файл, а затем компилирует файл исходного кода, чтобы получить объектный код класса GradeBook. Чтобы скрыть детали реализации элемент-функций GradeBook, программист класса предоставит программисту кода клиента только заголовочный файл MyGradeBook.h (который специфицирует интерфейс класса и его элементы данных) и объектный код класса GradeBook, который содержит инструкции машинного языка, представляющие элемент-функции GradeBook. Программисту кода клиента не передается файл исходного кода GradeBook, так что клиент остается в неведении относительно того, как реализованы элемент-функции класса.

    Коду клиента, чтобы использовать класс, необходимо знать только интерфейс GradeBook и, кроме того, он должен иметь возможность компоноваться с его объектным кодом. Поскольку интерфейс является частью определения класса в заголовочном файле GradeBook.h, программист кода клиента должен иметь доступ к этому файлу и включить его посредством #include в файл исходного кода клиента. Когда код клиента компилируется, компилятор использует определение класса в MyGradeBook.h для того, чтобы убедиться в корректности создания объектов класса GradeBook и манипуляций ими в функции main.

    Последним шагом построения исполняемого приложения является компоновка
    1. объектного кода функции main (т.е. кода клиента),
    2. объектного кода реализации элемент-функций класса GradeBook,
    3. объектного кода Стандартной библиотеки C++ для классов C++ (например, string), применяемых программистом класса и программистом кода клиента.

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

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

    С++ для начинающих Классы Первое знакомство

    Введение в ООП всегда вызывает затруднение у большинства студентов.

    • В стандарте C++ под классом (class) подразумевается пользовательский тип, объявленный с использованием одного из ключевых слов class, struct или union, под структурой (structure) подразумевается класс, определённый через ключевое слово struct, и под объединением (union) подразумевается класс, определённый через ключевое слово union.

    В качестве знакомства с классами я решил использовать обычное сложение двух чисел типа int
    Кажется самый распространенный пример обучения — это привести пример на геометрических фигурах. Но на мой взгляд это никакой конкретики не вносит (сугубо личное мнение).

    Задача: Сложить два числа через классы в C++

    Этап первый. Пишем пустую программу.
    Код C++ Пустая программа

    Этап второй. Объявляем класс
    Код C++ Объявление класса

    Этап третий. Подготавливаем класс описывая внутри всё для работы
    Код C++ Подготовка класса

    Этап четвертый. Работа с классом

    Код C++ Работа с классом

    Теперь я подробнее расскажу про важные моменты в этом коде
    1) Что такое класс и вообще зачем он нужен?

    В первую очередь класс является собственным типом данных.

    • Класс — это некоторая идея еще не существующего объекта, в которой воедино собраны все детали, все свойства и все нужные действия необходимые для этого объекта

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

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

    После создания пустого класса внутри этого класса прописывается вся информация для выполнения поставленной задачи. Важные моменты то, что внутри класса используются слова public, private и protected. Я заострю внимание на public и private
    Это модификаторы доступа. То что описано внутри public доступно для всей программы, а то что написано внутри private доступно только внутри класса. Чем-то очень похоже на локальные и глобальные переменные. Модификатор доступа в классе по умолчанию private, поэтому слово private: писать не обязательно. Ниже написаны две равнозначные записи

     

    Главный вопрос в том что, что прописывать в private, а что в public. Я если честно не знаю. Можно много спорить. Но попробую описать. В private стоит прописывать все детали вашей конструкции, в public только те функции и те данные, доступ к которым должен как-то происходить из функций вне класса.
    В приведенном примере на третьем этапе было определено так, что к деталям я отнес переменные x,y и к ним доступа кроме как внутри класса не дал, прописав их внутри private (по умолчанию private). Вместе с этим мне потребовались две отдельные функции. Первая функция ввод чисел, Вторая функция складывает числа. Как ни крути, логично, что доступ к этим функциям мне нужен извне класса, поэтому я сделал обе функции доступными для всей программы и доступ к ним могу получить практически в любом месте программы вне класса.

    Так как класс всего-лишь идея, то надо её перевоплотить в жизнь. Чтобы это сделать нужно объявить объект. Объект это экземпляр класса.
    Если у вас есть класс, но нет объекта, то вы как депутат голословный пустословите и обещаете, но на практике дел не делаете. Чтобы не быть «пустословом» обязательно создать объект, т.к. работать вы будете через этот объект. На четвертом этапе приведен пример создания объекта

    По сути класс есть структура. Отличается класс от структуры только модификатором доступа по умолчанию. Чтобы обратиться к элементу внутри класса нужно прописать объект и через точку тот элемент к которому обращаемся. Можно обращаться только к тем элементам класса, которые описаны внутри public: (имеется ввиду обращение извне)
    На четвертом этапе, кроме создания объекта (экземпляр класса), я обратился к функциям вовнутрь класса summa через созданный объект. Так как я сделал доступными для всей программы две функции, то доступ к ним затруднений не вызывает.
    Первая функция — ввод данных. При вводе данных я вывожу на экран нужную информацию и считываю с клавиатуры два числа. Эти числа запоминаются в переменных X,Y внутри класса. Напоминаю, что непосредственного доступа к этим X,Y из программы у меня нет. Функция внутри класса выступает в роли посредника
    Вторая функция — сложение двух чисел. Вы прекрасно видите, что никаких параметров и ничего в функцию я не передавал. Просто обратился к переменным X,Y и просто их просуммировал. Во время ввода данных введенные значения присвоились в переменные X,Y вовнутрь private. После этого присвоения я могу работать с этими X,Y почти как с глобальными переменными, разница от глобальных в том, что могу только в классе

    Еще один момент о котором я бы решил не отмалчиваться. В приведенном примере getch() и clrscr() надеюсь сможете поставить. (просто чтоб не отвлекать внимание не писал этих строчек). Я использовал немного разное написание функций. Я писал int main() и void get_xy() — функция main() всегда должна быть int, а другие функции не обязательно что-то обязаны вычислять и отдавать результаты. Если функция ничего не вычисляет для последующей обработки результата вычисления после завершения функции, то она не обязана отдавать результаты своих вычислений, это можно обозначать типом void, а вот сумма чисел обязана вернуть какое-то значение, так как произошло вычисление. В приведенном примере она возвращает сумму двух чисел, поэтому int sum_xy().

    Подвожу итоги

    • Класс есть структура, в которой доступ по умолчанию private
    • Класс — это собственный тип данных
    • Класс — это некоторая идея еще не существующего объекта, в которой воедино собраны все детали, все свойства и все нужные действия необходимые для этого объекта
    • Создается класс с помощью слова class (struct,union)
    • В классе class модификатор доступа по умолчанию private:
    • В классе struct модификатор доступа по умолчанию public:
    • То что описано внутри public доступно для всей программы, а то что написано внутри private доступно только внутри класса
    • Функции внутри класса называют методами класса (это я не писал, но знать надо)
    • Объект — это экземпляр класса
    • Объект есть воплощение вашей идеи, описанной в классе во что-то реально существующее
    • Доступ вовнутрь класса осуществляется по конструкции Объект.Элемент класса

    }

    Поиск

     
         
    
    
    Яндекс.Метрика

    НАГРАДИ АВТОРА САЙТА
    WEBMONEY
    R375024497470
    U251140483387
    Z301246203264
    E149319127674
    
    
    В свои 20 лет он знал более 9 опеpационных систем и ни одной женщины.

    Выражаю свою признательность

    • Максиму очень признателен за указание на мои ошибки и неточности.
    • Sergio ===> за оказание помощи в исправлении моих ошибок
    • Gen ===> за правильное стремление помочь другим новичкам и выявления моих ошибок