ООП экзамен МОА. Для экзамена. Свойсва ооп ссылки
![]()
|
Свойсва ООП![]() Ссылки Ссылка — это тип переменной в языке C++, который работает как псевдоним (синоним объявленного типа) другого объекта или значения. Ссылки должны быть инициализированы при создании. После инициализации изменить объект, на который указывает ссылка — нельзя. Ссылки чаще всего используются в качестве параметров в функциях. В этом контексте ссылка-параметр работает как псевдоним аргумента, а сам аргумент не копируется при передаче в параметр. const int &ref - value ссылка на константу int &const ref = value; константная ссылка Про void Тип void (пустой) синтаксически ведет себя как основной тип. Однако использовать его можно только как часть производного типа, объектов типа void не существует. Он используется для того, чтобы указать, что функция не возвращает значения, или как базовый тип для указателей на объекты неизвестного типа. void f() // f не возвращает значение void* pv; // указатель на объект неизвестного типа Переменной типа void* можно присваивать указатель любого типа. На первый взгляд это может показаться не особенно полезным, поскольку void* нельзя разыменовать, но именно это ограничение и делает тип void* полезным. Главным образом, он применяется для передачи указателей функциям, которые не позволяют сделать предположение о типе объекта, и для возврата из функций нетипизированных объектов. Чтобы использовать такой объект, необходимо применить явное преобразование типа. Преобразование типов В программировании на языке Cи явное преобразование типов данных выполняется с помощью оператора (). Внутри круглых скобок мы пишем тип, в который нужно конвертировать. Этот способ конвертации типов называется конвертацией C-style. Например: float x = (float)i1 / i2; В языке C++ есть еще один оператор явного преобразования типов данных — оператор static_cast. Оператор static_cast лучше всего использовать для конвертации одного фундаментального типа данных в другой: float x = static_cast Основным преимуществом оператора static_cast является проверка его выполнения компилятором во время компиляции, что усложняет возможность возникновения непреднамеренных проблем. New, delete, :: char *pch = new char[BUFFER_SIZE]; Если запрос имеет нулевые байты хранилища, функция operator new возвращает указатель на отдельный объект. То есть повторные вызовы operator new возвращают разные указатели. Если недостаточно памяти для запроса на выделение, operator new создает std::bad_alloc исключение. Или возвращает, nullptr Если вы связались с поддержкой без вызова operator new. Память, выделенная динамически с помощью new оператора, может быть освобождена с помощью delete оператора. delete[] pMem; С++ используется для уточнения, в каком пространстве имён следует искать идентификатор. Пространство имен (namespace) – это способ объединения логически связанных объявлений под общим именем. Аргументы по умолчанию Аргумент по умолчанию – это такой аргумент функции, который программист может не указывать при вызове функции. Аргумент по умолчанию добавляется компилятором автоматически. Чтобы использовать аргументы по умолчанию в функции, эта функция должна быть соответствующим образом объявлена. Аргументы по умолчанию объявляются в прототипе функции. Общая форма объявления функции, которая содержит аргументы по умолчанию returned_type FunName(type1 v1 = val1, type2 v2 = val2, ..., typeN vN = valN) { // тело функции } Во время объявления функции, аргументы по умолчанию задаются только один раз. Здесь возможны два случая. Первый, если функция имеет прототип и реализацию. Второй случай, если функция не имеет прототипа, а имеет только реализацию. В первом случае (с прототипом), аргумент по умолчанию задается только в прототипе функции (а не в реализации). Во втором случае, аргумент по умолчанию задается в реализации функции, поскольку нет прототипа функции. Аргументы (параметры) по умолчанию должны следовать после объявления обычных аргументов. Если объявить аргументы по умолчанию первыми, а за ними объявить обычные аргументы, то это будет ошибка. Использование функций C в C++ #include < cstdio> Заголовочный файл нового стиля, функции вызываются через :: Inline (встраиваемые) функции Подставляемые или встраиваемые (inline) функции – это функции, код которых вставляется компилятором непосредственно на место вызова, вместо передачи управления единственному экземпляру функции. Если функция является подставляемой, компилятор не создает данную функцию в памяти, а копирует ее строки непосредственно в код программы по месту вызова. Это равносильно вписыванию в программе соответствующих блоков вместо вызовов функций. Таким образом, спецификатор inline определяет для функции так называемое внутреннее связывание, которое заключается в том, что компилятор вместо вызова функции подставляет команды ее кода. Подставляемые функции используют, если тело функции состоит из нескольких операторов. Однако следует обратить внимание, что использование подставляемых функций не всегда приводит к положительному эффекту. Если такая функция вызывается в программном коде несколько раз, то во время компиляции в программу будет вставлено столько же копий этой функции, сколько ее вызовов. Произойдет значительное увеличение размера программного кода, в результате чего ожидаемого повышения эффективности выполнения программы по времени может и не произойти. Перечислим причины, по которым функция со спецификатором inline будет трактоваться как обычная не подставляемая функция: подставляемая функция является рекурсивной; функции, у которых вызов размещается до ее определения; функции, которые вызываются более одного раза в выражении; функции, содержащие циклы, переключатели и операторы переходов; функции, которые имеют слишком большой размер, чтобы сделать подстановку. Перегрузка функций – это создание нескольких функций с одним именем, но с разными параметрами. Под разными параметрами понимают, что должно быть разным количество аргументов функции и/или их тип. То есть перегрузка функций позволяет определять несколько функций с одним и тем же именем и типом возвращаемого значения. Разная сигнатура. Сигнатуру функции (от англ. signature — подпись, нечто идентифицирующее) в языке C++, определяет не только имя функции, но и тип параметров вызова функции, а также, тип, который функция возвращает. Дружественные классы Дружественная функция — это функция, которая имеет доступ к закрытым членам класса, как если бы она сама была членом этого класса. Во всех других отношениях дружественная функция является обычной функцией. Ею может быть, как обычная функция, так и метод другого класса. Для объявления дружественной функции используется ключевое слово friend перед прототипом функции, которую вы хотите сделать дружественной классу. Классы, структуры, объединения Синтаксически класс похож на структуру. Класс и структура имеют фактически одинаковые свойства. В C++ определение структуры расширили таким образом, что туда, как и в определение класса, удалось включить функции-члены, в том числе конструкторы и деструкторы. Таким образом, единственным отличием между структурой и классом является то, что члены класса, по умолчанию, являются закрытыми, а члены структуры — открытыми. Когда объявлено объединение, компилятор автоматически создает переменную достаточного размера для хранения наибольшей переменной, присутствующей в объединении. Для доступа к членам объединения используется синтаксис, применяемый для доступа к структурам - с помощью операторов «точка» и «стрелка». Безусловные объединения – объединения, содержащие пользовательские типы данных. Совместимость C C++ По большей части совместимость есть. Но есть несколько но: 1) Некоторые сишные конструкции конкретный C++ компилятор как бы поддерживает, но по стандарту не должен (например, VLA массивы int array[rand()];). 2) Некоторые конструкции и сишный компилятор по стандарту поддерживать не должен, но вместо этого только пальцем грозит. А C++-компилятор вместо того чтобы грозить пальцем, сразу шлет подальше (неявный каст double*->int* к примеру). 3) Ну и наконец, есть узкий класс конструкций которые Си официально поддерживает, а плюсы нет (неявный каст void*->int*). Класс и объект Объект – структура данных, содержащая описание свойств внешнего объекта программирования. Метод – функция, работающая с объектом. Класс – описание структуры объекта и методов работы с ним. Класс – тип данных, определяемый программистом, объект –переменная классаэ Область видимости Область видимости переменных — это те части программы, в которой пользователь может изменять или использовать переменные в своих нуждах. Каждый класс представляет отдельную область видимости. Имена членов класса локальны в этом классе. Оператор разрешения контекста имеет самый высокий приоритет и применяется в двух формах: унарная — ссылается на внешний контекст; бинарная — ссылается на контекст класса. Унарная форма записи: :: Идентификатор Бинарная форма записи: ИмяКласса :: Идентификатор Опережающее объявление класса Предварительное объявление является таким типом объявления, при котором сборщик(компилятор) имеет возможность разрешить ссылки из различных частей программы. Предварительное объявление позволяет программисту ссылаться на объекты, о которых компилятор ещё не знает, но которые будут определены в процессе компиляции позже. В программировании предварительное объявление - это объявление идентификатора (типа, переменной или функции), для которого программист ещё не дал полного определения. Объявление идентификатора требуется компилятору для того, чтобы знать тип (размер) идентификатора, но не его значения (в случае переменных). Использование спецификатора класса памяти static. Статический элемент класса Спецификатор static указывает компилятору на хранение локальной переменной во время всего жизненного цикла программы вместо ее создания и разрушения при каждом входе в область действия и выходе из неё. Следовательно, возведение локальных переменных в ранг статистических позволяет поддерживать их значения между вызовами функций. Модификатор ststic можно также применять к глобальным переменным. В этом случае область видимости такой переменной ограничивается файлом, В котором она объявлена, это означает, что переменная будет иметь внутреннюю привязку. Внутренняя привязка говорит о том, что модификатор известен только внутри своего файла. В языке C++ использование спецификатора ststic для данных-членов класса приводит к созданию только одной копии этих членов, совместно используемой всеми объектами класса. При создании объектов класса память под статический элемент данных не выделяется, все объекты работают с единственным статическим компонентом. Обращаться к статическому компоненту класса можно как к обычному компоненту через имя уже существующего объекта, словно он является частью этого объекта. При этом необходимо учитывать, что, обращаясь к компонентному данному через имя одного объекта, мы изменяем его значение и для всех остальных объектов того же класса. Необходимо также отметить, что на статические компоненты класса действуют ограничения по области видимости, задаваемые ключевыми словами public, protected и private в теле класса. Константные объекты и функции-члены. Для написания программ необходимо пользоваться принципом наименьших привилегий , т.е. задавать объекту только те привилегии, к-ые ему необходимы Используя слово const—указывающее на то, что объект не может быть модифицирован. Когда используется объект, объявленный с модификацией const , то для него могут вызываться только те ф-ции класса, к-ые так же объявлены с модификатором const. Такие ф-ции не могут изменить состояние объекта. Конструкторы и деструкторы не могут быть объявлены с модификатором const. Указатель this Ключевое слово this представляет собой неявно определенный указатель на сам объект. С его помощью метод класса определяет, с данными какого объекта ему предстоит работать. Каждый метод класса неявно содержит в качестве поля данных указатель. Ключевое слово this представляет собой неявно определенный указатель на сам объект. С его помощью метод класса определяет, с данными какого объекта ему предстоит работать. Каждый метод класса неявно содержит в качестве поля данных указатель Указатели на член класса Кроме указателей на объекты класса, в С++ существуют указатели на от дельные члены класса. Указатель на отдельный член существенно отличается от обычного указателя, как по способу объявления, так и по методам использования. Указатель на член класса задает смещение этого члена. В некотором смысле это относительный адрес члена класса в структуре класса. Указатели на члены класса могут ссылаться как на поля, так и на методы. Объявление указателей на поля и на методы выполняется по-разному. При объявлении указателя на поле класса указывается тип для указателя, со впадающий с типом поля, на которое ссылается указатель, а перед именем указателя, кроме обычного в таких случаях оператора *, через опера тор расширения контекста ::, указывается и имя класса. Вложенный класс class или struct также могут содержать другое определение class / struct внутри себя, которое называется «вложенным классом»; в этой ситуации содержащий класс называется «охватывающим классом». Вложенное определение класса считается членом входящего класса. За пределами закрывающего класса доступ к вложенным классам осуществляется с помощью оператора области видимости. Однако изнутри закрывающего класса вложенные классы могут использоваться без квалификаторов. Как и в случае не-вложенного class / struct , функции-члены и статические переменные могут быть определены либо внутри вложенного класса, либо в охватывающем пространстве имен. Тем не менее, они не могут быть определены внутри охватывающего класса, поскольку он считается другим классом, чем вложенный класс. class Outer { class Inner { // friend class Outer; int x; }; Inner in; public: int get_x() { return in.x; // Error: int Outer::Inner::x is private. // Uncomment "friend" line above to fix. } }; Конструкторы, деструкторы Конструктор — функция, предназначенная для инициализации объектов класса. Конструктор, не требующий параметров, называется конструктором по умолчанию. Как правило, при создании нового объекта на базе уже существующего происходит поверхностное копирование, то есть копируются те данные, которые содержит объект-источник. При этом если в объекте-источнике имеются указатели на динамические переменные и массивы, или ссылки, то создание копии объекта требует обязательного дублирования этих объектов во вновь создаваемом объекте. С этой целью вводится конструктор копии, который автоматически вызывается во всех перечисленных случаях. Он имеет единственный параметр — ссылку на объект-источник. Определяемый пользователем класс имеет конструктор, который обеспечивает надлежащую инициализацию. Для многих типов также требуется обратное действие. Деструктор обеспечивает соответствующую очистку объектов указанного типа. Имя деструктора представляет собой имя класса с предшествующим ему знаком «тильда» . Так, для класса X деструктор будет иметь имя X(). Многие классы используют динамическую память, которая выделяется конструктором, а освобождается деструктором. Программирование методов. Принцип модульности Помимо хранения данных, классы могут содержать и функции! Функции, определенные внутри класса, называются методами. Методы могут быть определены, как внутри, так и вне класса. Модульность – разбиение задач на более мелкие Программирование методов – содержательное наполнение класса – позволяет использовать принципы модульного программирования и создавать эффективный программный код. Основной эффект модульности – многократное выполнение одного и того же кода в различных контекстах, обеспечивается различными способами: · представление алгоритмической компоненты класса в виде множества мелких методов, вызывающих друг друга; · создание вспомогательных (локальных) объектов при выполнении операций над основными объектами класса (текущим и передаваемым через параметры); Способы передачи параметров в методы с++ Передача параметров в функцию может осуществляться по значению и по адресу. При передачи данных по значению функция работает с копиями фактических параметров, и доступна к исходным значениям аргументов у нее нет. При передачи по адресу в функцию передается не переменная, а ее адрес, и, следовательно, функция имеет доступ к ячейкам памяти, в которых хранятся аргументов. Таким образом, данные, переданные по значению, функция изменить не может, в отличие от данных, переданных по адресу. Если требуется запретить изменение параметра внутри функции, используют модификатор const. Конвейер ссылок, конвейер значений В обоих из них возвращаемый результат является объектом того же класса, поэтому такие функции можно объединять в цепочки – «конвейеры». Разница состоит в том, что в одном случае «по конвейеру» передается ссылка, т.е. сам объект – операнд, а в другом случае – копия (значение). Соответственно, и называются они конвейером ссылок и конвейером объектов (значений). В конвейере ссылок метод получает операнды по ссылке (или указателю, как, например, текущий объект). Он не создает «лишних» объектов и все необходимые действия производит над объектами-оригиналами по ссылке, изменяя их содержимое. В качестве результата возвращается ссылка на текущий объект или на объект – формальный параметр. В main передача ссылки выглядит как синтаксическая передача имени объекта со входа на выход, т.е. последовательность методов выполняется над одним и тем же объектом. В конвейере значений результатом метода является значение объекта класса. На практике это означает, что в вызывающем коде транслятор создает временный объект, в который оператор return копирует значение объекта из внутреннего контекста. Цель такого копирования заключается в сохранении неизменными входных операндов (результат – новый объект, отличный от исходных). Поэтому в теле метода необходимы вспомогательные объекты, в которые помещаются копии входных. Копирование объектов сопровождается явным или автоматическим вызовом конструктора копирования, создающим независимую копию динамических данных объекта. Классы, содержащие объекты других классов Список аргументов должен соответствовать какому-нибудь из конструкторов класса к которому он принадлежит. Именно этот конструктор и будет вызываться для таких членов-объектов класса. При использовании классов агрегатов следует учесть, что конструкторы членов-объектов класса вызываются раньше, чем для класса владельца. Элементы - данные некоторого класса могут быть объектами других классов, содержащих свои конструкторы и деструкторы. В объектно-ориентированной методологии известно такое понятие HASA relationship. Инициализация элементов-объектов осуществляется через список инициализации (constructor initializer). Часть заголовка конструктора начинающаяся двоеточием, называется списком инициализации. Он представляет собой перечисление имен объектов членов класса со списком аргументов в скобках. Отдельные члены должны быть проинициализированы следующим образом: имя_члена (список аргументов). Список аргументов должен соответствовать какому-нибудь из конструкторов класса к которому он принадлежит. Именно этот конструктор и будет вызываться для таких членов-объектов класса. // класс с объектами-членами другого класса class A { ........... public: A(int n=0) {...}; A() {...}; }; class B { ........... public: B(double x=0) {...}; B() {...}; }; class D { const A a; B b; public: D(double x,int i); D(double x); D(); D(); }; // реализация D::D(double x,int i):b(x),a(i) { ....... } D::D(double x):b(x) { ....... } D::D():b(0) { ....... } В этом примере класс D создает два объекта классов A и B. Для инициализации a и b используется список инициализации. При Порядок вызовов конструкторов членов-класса определяется не списком инициализации, порядком объявления переменных класса. Список инициализации членов Хотя в плане синтаксиса языка C++ вопросов никаких нет — всё корректно, но более эффективно — использовать инициализацию, а не присваивание после объявления. Как мы уже знаем из предыдущих уроков, некоторые типы данных (например, константы и ссылки) должны быть инициализированы сразу. Способы инициализации: int value1 = 3; // копирующая инициализация double value2(4.5); // прямая инициализация char value3 {'d'} // uniform-инициализация Поверхностное копирование Поскольку язык C++ не может знать наперед всё о вашем классе, то конструктор копирования и оператор присваивания, которые C++ предоставляет по умолчанию, используют почленный метод копирования — поверхностное копирование. Это означает, что C++ выполняет копирование для каждого члена класса индивидуально (используя оператор присваивания по умолчанию вместо перегрузки оператора присваивания и прямую инициализацию вместо конструктора копирования). Когда классы простые (например, в них нет членов с динамически выделенной памятью), то никаких проблем с этим не должно возникать. Создание объектов с различным временем жизни Статические объекты создаются при запуске программы в сегменте данных и существуют до закрытия. Конструкторы для таких объектов вызываются неявно в порядке поступления объектов на вход компоновщика. Деструкторы вызываются при окончании работы программы в порядке обратном порядку вызова конструктора. Локальные (автоматические) объекты создаются в стеке в момент входа в блок или функцию и уничтожатся при выходе оттуда. Конструкторы вызываются неявно в момент определения объекта при каждом очередном входе в блок программы в порядке определения. Деструкторы для каждого объекта вызываются неявно при выходе из блока в порядке обратном порядку вызова конструктора. В стек могут создаваться временные объекты, необходимые для вычисления выражений и вызова функций. Порядок вызова конструкторов определяется порядком вычисления. Деструкторы для временных объектов выполняются по окончанию операторов, в которых потребовались временные переменные. Динамические объекты создаются, инициализируются и уничтожатся по требованию программиста при помощи операторов new и delete. Операция new кроме выделения памяти определяет вызов соответствующего конструктора. Delete – соответствующий деструктор. Для объектов пользовательского типа надо пользоваться только new и delete, а не fmalloc, потому что malloc не вызывает конструктора. То же самое происходит и при delete. Прочая информация int a1 = 1; 1 – литерал Разыменовывание указателя – получение значения В случае создания двух переменных с одинаковым именем (одна из которых является глобальной, а другая локальной) при использовании в блоке, в котором была объявлена локальная переменная, можно использовать и глобальную переменную. Для ее использования нужно всего лишь применить глобальный оператор разрешения. Глобальный оператор разрешения — это два подряд поставленные двоеточия, с помощью которых мы говорим компилятору, что хотим использовать глобальную переменную, а не локальную. В C ++ есть несколько типов наследования: публичный (public)- публичные (public) и защищенные (protected) данные наследуются без изменения уровня доступа к ним; защищенный (protected) — все унаследованные данные становятся защищенными; приватный (private) — все унаследованные данные становятся приватными. Поскольку rParent является ссылкой на родительскую часть объекта child, то, обычно, при обработке rParent.getName() вызывался бы Parent::getName(). Тем не менее, поскольку Parent::getName() является виртуальной функцией, то компилятор понимает, что нужно посмотреть, есть ли переопределения этого метода в дочерних классах. И компилятор находит Child::getName()! |