Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Правила перегрузки операторов
• Для постфиксных унарных операций в функцию-оператор последним аргументом передается фиктивный параметр типа int • Для встроенных операций их интерпретация определяется как комбинация других операций • Для пользовательских типов ответственность за соблюдение таких правил целиком лежит на программисте
• Перегрузка оператора может помочь писать интуитивно понятный и «красивый» код. • При перегрузке операторов нужно «играть по правилам». Некоторые из них проверит компилятор, за некоторыми нужно следить самостоятельно • Не злоупотребляйте переопределением операторов, смысл операторов должен быть понятен другим программистам • Косвенное обращение Рассмотренные способы обращения к функции являются примерами непосредственного ее вызова, точно так же, как ранее непосредственно использовались значения переменных. Но при помощи указателя можно было получить доступ к содержимому переменной и косвенным образом, аналогичный способ существует и для обращения к функции.
int (*funcptr)(int, int);
Этот пример объявляет переменную funcptr типа указатель на функцию, возвращающую результат типа int и имеющую 2 параметра типа int. При объявлении указателя на функцию запись выглядит слегка шиворот-навыворот, но так уж требует Си: сначала мы указываем тип результата функции, затем обязательно в круглых скобках идентификатор (не забудьте про звездочку - признак указателя), а затем, опять в круглых скобках, список типов параметров функции.
typedef int (*t_func)(int, int); t_func funcptr;
funcptr = (t_func)0x1000; funcptr(3, 12); // вызов функции с параметрами по абсолютному адресу
так как тип указателя (void *) совместим с любым иным типом указателя. Индексирование Перегрузка оператора индексирования позволяет получать значения массивов, заключенных в объект, более простым и привычным способом, и это также способствует лучшей читаемости и пониманию исходного кода программ. Оператор [] может быть перегружен, чтобы получать единственный аргумент произвольного типа и возвращать произвольный тип в качестве своего значения. Поскольку оператор [] может вызываться лишь с одним аргументом, для имитации многомерных массивов часто применяют анонимные экземпляры. Хотя оператор [] вызывается лишь с одним аргументом, этот умеренно неуклюжий синтаксис позволяет создать произвольное количество псевдоаргументов. Вызов функции new и delete. В языке программирования C++ оператор delete возвращает память, выделенную оператором new, обратно в кучу. Вызов delete должен происходить для каждого вызова new, чтобы избежать утечки памяти. После вызова delete объект, указывающий на этот участок памяти, становится некорректным и не должен больше использоваться. Многие программисты присваивают 0 (нуль-указатель) указателям после использования delete, чтобы минимизировать количество ошибок программирования. Однако нужно отметить, что удаление нуль-указателя фактически не имеет эффекта, так что нет необходимости проверять нуль-указатель перед вызовом delete. В языке программирования C++, new — оператор, обеспечивающий выделение динамической памяти в куче. За исключением формы, называемой «размещающей формой new», new пытается выделить достаточно памяти в куче для размещения новых данных и, в случае успеха, возвращает адрес свежевыделенной памяти. Однако, если new не может выделить память в куче, то он передаст (throw) исключение типа std:: bad_alloc. Это устраняет необходимость явной проверки результата выделения. Для освобождения памяти используется операция (операторная функция) delete. Подобно операторной функции new, delete также является статическим членом класса. В контексте выражений размещения и удаления могут быть использованы стандартные операции C++ new и delete, а может быть обеспечен вызов операторных функций operator new и operator delete. Согласно грамматике C++, основным операндом для символа операции new в выражении размещения является заключённое в круглые скобки ИмяТипа, либо ИмяТипаNew (без скобок), которое разворачивается в конструкцию, содержащую информацию о размерах размещаемого массива Билет №17. Шаблоны На сцену выходит механизм шаблонов — усовершенствованный макропроцессор для директив #define. Шаблоны представляют собой ничто иное, как макросы без всех перечисленных ограничений. Они могут быть вложенными. Вам не придется беспокоиться о дублировании их функций. Большинство отладчиков C++ при возникновении ошибки правильно указывает строку шаблона. Размер шаблона не вызовет никаких проблем. Наконец, вам не придется уродовать свою прекрасную программу закорючками вроде \ и ##. Если вы собираетесь использовать шаблоны, привыкайте к тому, что в вашей речи будет часто звучать термин параметризованный (parameterized). Шаблоны используются для создания параметризованных типов (обычно классов) и параметризованных функций. Параметризованные типы Параметризованный тип внешне представляет собой обычное объявление класса, которому предшествует магическое заклинание template < c1ass Type>, где Type — выбранное вами символическое имя (остальные элементы задаются жестко). Всюду, где символическое имя Type (или другое имя) встречается в объявлении класса оно интерпретируется как макрос, вместо которого при использовании класса подставляется конкретный тип. Параметризованные функции Параметризованные функции объявляются точно так же — перед их объявлениями указывается формула template.... Синтаксис шаблона должен повторяться как при объявлении, так и при определении функции. Помните, шаблоны на самом деле являются макросами, поэтому они должны находиться в файлах.h. Если определение будет находиться в файле.срр, программа работать не будет (если только это не единственный файл.срр, в котором вызывается данная функция). Передача параметра Многочисленные символы < и > вызывают изрядную путаницу, поскольку C++ не всегда последователен. Вообще говоря, < Туре> следует указывать везде, кроме трех мест в объявлениях классов или определениях их функций: 1. За ключевым словом class в самом начале. 2. При указании имени конструктора. 3. При указании имени деструктора. Аргументы конструкторов и деструкторов должны быть параметризованными, как и все использования имени класса за исключением трех указанных случаев. При любом использовании параметризованного типа или функции необходимо указывать параметр. Было бы намного проще, если бы C++ просто требовал присутствия параметра во всех случаях, но это же C++... Вдобавок можно сэкономить несколько символов в исходном тексте программы. В трех указанных ситуациях компилятор может сделать разумные предположения по поводу отсутствующих символов. Шаблоны с несколькими параметрами Тип может иметь более одного параметра, хотя такие ситуации встречаются довольно редко. Увидев такой класс, я обычно затеваю с автором долгую беседу о принципах построения программ. Тем не менее, иногда использование многоаргументных шаблонов бывает оправданным. Синтаксис выглядит аналогично, разве что вместо < c1ass Type> используется список типа < c1ass Type1, class Type2>. Наконец, параметр не обязан быть классом. Он может быть структурой или еще чем-нибудь, хотя именно классы прочно удерживают ведущие позиции на рынке параметров. Долой вложенные параметризованные типы! Увы, такая возможность существует, но пожалуйста, пользуйтесь ею с максимальной осторожностью. Вложенные шаблоны не только плохо читаются, но и генерируют огромное количество кода при расширении. Помните, что при использовании шаблона самого верхнего уровня будут расширены все шаблоны.
Последний пункт очень важен. Речь идет о неявных требованиях к типу – параметру шаблона Эти требования выясняются только при конкретизации класса. Например, на слайде 31 я забыл убрать параметр по умолчанию 0 для параметра конструктора класса Link Это накладывает ограничение на тип, который можно использовать в качестве контейнера: он должен обязательно приводиться к целому числу.
Если такое приведение невозможно, конкретный класс не будет скомпилирован.
Фабрика-шаблон
Фабрика-шаблон (С++) Команды чтения из файла и создания теперь не зависят от конкретики; это значит, что Мы можем добавлять новые овощи сколько душе угодно без вмешательства в код взаимодействия с пользователем. Более того, новые овощи можно добавлять «на лету», то есть в идеале даже без перекомпиляции программы Плохая новость – на каждый овощ нужна собственная фабрика. Побочные эффекты · Application теперь отвечает и за создание объектов, кроме своих прямых обязанностей – взаимодействия с пользователем, чем нарушает принцип??? · Интерфейс «создатель» может создавать только овощи, и ничего больше, чем нарушает принцип!!! (Если захочется создавать фрукты, потребуется другая иерархия классов-создателей) ??? - единственности ответственности !!! - инвертирования зависимостей
Популярное:
|
Последнее изменение этой страницы: 2016-07-14; Просмотров: 567; Нарушение авторского права страницы