Главная » Просмотр файлов » лекции (1998) (Буров)

лекции (1998) (Буров) (1161123), страница 13

Файл №1161123 лекции (1998) (Буров) (лекции (1998) (Буров)) 13 страницалекции (1998) (Буров) (1161123) страница 132019-09-19СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 13)

char body[50];

int top;

void Push (char x);

char Pop ();

static int Errcode;

};

Здесь у нас stack одновременно и имя модуля и типа, нам не надо придумывать два различных имени.

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

Заметим, что мы написали только определение класса. Где следует писать реализацию класса? В любом месте ниже:

void Stack::Push(char x) {

this->body[this->top++] = x;

}

Что сразу бросается в глаза? Конечно, тот факт, что и в Modula-2 и в других языках мы передавали функциям Push и Pop по два параметра. Здесь же для Push передается один параметр, для Pop – вообще ни одного. Одним из фундаментальных свойств класса является то, что в каждую функцию или процедуру класса неявно передается ссылка на экземпляр класса, ссылаться на который можно с помощью ключевого слова this. Но, вообще говоря, в C++ считается, что все имена полей локализованы, поэтому мы можем опускать this-> и писать следующим образом:

void stack::Push(char x) {

body[top++]=x;

}

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

Возникает вопрос – откуда берется этот неявный параметр? Поскольку stack – тип данных, то мы можем объявлять переменные этого типа:

stack S;

и писать:

S.Push(‘e’);

теперь понятно, что значение this берется из переменной S.

Заметим, что у нас есть вполне естественный и понятный синтаксис:

<имя объекта>.<имя члена>,

такой же, какой был в языке С. Но теперь он стал содержать в себе гораздо больше – если <имя члена> - функция, то в качестве неявного параметра ей передается указатель на соответствующий экземпляр объекта.

Заметим, что здесь степень интеграции гораздо выше. И это не только вопрос удобства.

Посмотрим немного на то, сколько места занимает объект типа Stack: массив body и переменная top:

BODY

TOP

Errcode в этой области не размещается, т.к. он размещается «где-то там» в единственном экземпляре, чтобы быть доступным для каждого объетка класса. Это действительно переменная класса, она одна на всех.

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

Имеет ли смысл обращение:

S.Errcode?

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

S2.Errcode

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

stack::Errcode

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

А какой смысл в статических функциях? Чем они должны быть непохожи на обычные функции? Это функции, не имеющие смысла для конкретного члена, но имеющие смысл для класса в целом. Например, если они оперируют только статическими переменными.

Предположим, что мы не хотим иметь возможность доступа к Errcode извне (чтобы не испортить ее), а хотим, чтобы только функции Push и Pop могли ее модифицировать. Это сделать достаточно просто. Мы объявляем Errcode, как private, оно будет означать, что только функции-члены данного класса могут обращаться к данной переменной. Как к ней получить доступ извне? Следует написать функцию, которая будет возвращать значение Errcode. Она, очеведно, должна быть статической.

static int GetError () {return Errcode;}

private static Errcode;

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

int GetError () {

body[top++]=0;

};

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

Обратим внимание на то, что в предпоследнем примере тело функции GetError () было написано прямо в определении класса. Это допустимо. Мало того, в Java только так и можно делать, там нет отдельного места для реализации функций. Впрочем, такие вещи, как создание определений на основе полного модуля следует отдавать на откуп интегрированной среде или каких-то внешних средств, так как встраивать такие вещи в язык – несколько лишнее.

Рассмотрим еще один интересный ньюанс. Дело в том, что современный архитектуры процессоров подразумевают конвейерность, то есть когда процессор за один такт обрабатывает несколько команд, эти команды загружаются сразу по несколько штук. Очевидно, что операция перехода заставляет очищать конвейер и заполнять его заново другими инструкциями. Поэтому на уровне микроархитектуры подобные функции, как GetError, возвращающие только значения переменных являются крайне неэффективным средством. Вирт, например, в Oberon-2 специально ввел переменные, доступные только для чтения, чтобы разрешить эту проблему. Так как Страуструп хотел перенять из языка С в C++ все его хорошие качества, в том числе и эффективность, то он сделал следующее: inline функцию. Это ключевое слово - подсказка компилятору, что данную функцию можно включить напрямую, так как вызов ее (а следовательно операции со стеком, сбросом конвейера и все это несколько раз) будет просто дороже.

Возвращаясь, к определению класса отметим, что реализация функции внутри определения класса C++ означает как раз то, что ее следует включить inline. Это, конечно, не более, чем рекомендация компилятору, т.к. он имеет полное право ее проигнорировать. Как правило игнорируется inline у функций, где есть любые операторы перехода, слишком длинный код. Заметим, что inline концепция более общая, чем, например, переменные read-only.

Лекция 11

Мы с вами определили, что для того, чтобы связать с именем типа не только соответствующую структуру данных, но и соответствующий набор операций и атрибутов данных, необходима некая логическая структура, а именно, модуль. В разных языках программирования модуль имеет разные виды. Мы рассмотрели два подхода – концепцию модуля как обертки (Модула-2, Оберон, Ада), и подход С++, который, в некотором смысле, более элегантен. Понятие модуля несколько ограничено (оно должно быть шире, чем просто определение типа данных), поэтому в С++ введена новая конструкция, которая называется класс. При этом, структура (struct) является тем же классом, и отличается только тем, что у нее по умолчанию все члены открыты (public), тогда как у класса по умолчанию все члены скрыты (private).

Со структурой можно работать точно так же как и с классом, хотя полностью организовать совместимость нельзя из-за "дурных" свойств языка Си, в котором при описании переменной структурного типа необходимо использовать ключевое слово struct перед именем соответствующего типа. Образуется как бы новое пространство имен, часто можно встретить функцию такого рода: struct time time(…). И если структура описана внутри другой структуры, то она не является локальной и может свободно использоваться также как и внешняя структура. При описании класса, имя этого класса становится обычным именем типа. Причем отказаться от такого подхода к структурам в С++ нельзя было из-за соображений эффективности.

Но вернемся к классам. Класс состоит из членов-данных и из членов-функций. Есть понятие статических членов класса (это могут быть и данные и функции), которые не принадлежат ни к одному экземпляру класса, но доступны для всех. При этом, статические функции от обычных функций отличаются тем, что в не статическую функцию неявно передается указатель this, который указывает на объект данного класса (в языке Smaltalk есть аналогичное понятие Self, которое, однако, не является указателем). Статические функции имеют смысл только в пределах самого класса, поэтому к ним имеет смысл обращаться с помощью несколько другой нотации: имя_класса::имя_стат_функции.

Механизм классов более элегантен, чем механизм модулей. Нам не нужна дополнительная обертка. Для того чтобы описать класс Stack достаточно написать:

struct Stack {

char* body;

int top;

};

В механизме классов в С++ есть несколько "изюминок", которые, с одной стороны, несколько усложняют реализацию и понимание, с другой стороны, решают некоторые наболевшие проблемы, которые не решаются с помощью модулей. Прежде всего, – это проблемы инициализации и, соответственно, уничтожения объектов. Если мы выберем динамическую реализацию стека, то возникает необходимость его удалить после завершения работы с ним. В языке Ада решалась проблема инициализации стека (с помощью параметризации), но не решалась проблема его удаления. Но для более сложных структур в Аде не всегда можно решить и проблему инициализации, поэтому приходилось писать некоторую процедуру Init, которая и занималась инициализацией. Однако, в этом случае, компилятор не сможет проконтролировать наличие инициализации, и нет никаких средств для выполнения этой процедуры автоматически. Также отсутствует механизм уничтожения ресурсов, взятых при инициализации. Проблема деструкции более насущная, потому что компилятор в принципе может отследить неинициализированные переменные (и выдать warning), и современные оптимизирующие компиляторы этим занимаются. Проблема статической разрешимости неинициализированных объектов алгоритмически не разрешима, но еще более сложна проблема уничтожения объектов.

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

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

Пусть у нас есть класс X. Синтаксически, конструктор имеет то же самое имя X(…). У этой функции нет никакого возвращаемого значения (при этом, это не void-функция). И не нужно думать, что у этой функции возвращаемое значение int (это тип по умолчанию). В зависимости от видов параметров и, следовательно, от его семантики конструкторы делятся на четыре класса:

  • 1. Конструкторы умолчания X();

  • 2. Конструкторы преобразования X(T); X(T&); X(const T&);

  • 3. Конструкторы копирования X(X&); X(const X&);

  • 4. Остальные конструкторы

Первые три типа конструктора (каждый из них) имеют дополнительную семантику по сравнению с четвертым типом конструктора. Эта семантика связана с тем, чтобы компилятор автоматически вставлял действия по соответствующей инициализации. Страуструп написал, что конструктор – это то, что кусок памяти превращает в объект. Когда в языке Си мы делали malloc, то это не было инициализацией – это просто отведение куска памяти.

Инициализация может задаваться пользователем, и бывает системная (или стандартная) инициализация. Пользовательская инициализация – это те действия, которые заданы в теле соответствующего конструктора. Например, в случае структуры Stack, полное описание должно включать в себя отведение памяти.

struct Stack {

char* body;

int top;

int size;

};

Stack::Stack(int sz) { // Это конструктор преобразования

body = new char [size=sz]; // Ошибки не обрабатываем

top = 0;

};

Где же происходит инициализация? В данном случае инициализация только пользовательская, и никакой системной инициализации транслятор не вставляет, потому что у нас простое тело стека. Поскольку вызов конструктор вставляется автоматически, компилятор должен знать, какой параметр передать конструктору. Поэтому переменная типа Stack описывается так: Stack S(20). При этом объявлении и вызывается конструктор, который превращает кусок памяти в стек.

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

При распределении динамической памяти в С++ уже нельзя обойтись стандартной библиотекой (функциями malloc и free), потому что нужно указать, что при выделении памяти под объект должен еще выполняться конструктор. Именно по этому в С++ появились зарезервированные слова new и delete. В С++ есть возможность переопределить динамическое распределение памяти в операторах new и delete. Соответственно, инициализация объекта будет выглядеть так:

Характеристики

Тип файла
Документ
Размер
1,12 Mb
Тип материала
Высшее учебное заведение

Список файлов лекций

Свежие статьи
Популярно сейчас
Как Вы думаете, сколько людей до Вас делали точно такое же задание? 99% студентов выполняют точно такие же задания, как и их предшественники год назад. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6352
Авторов
на СтудИзбе
311
Средний доход
с одного платного файла
Обучение Подробнее