Реферат по предмету "Информатика, программирование"


Переход от С к С++

Малышев Сергей Михайлович
Хочусразу же сказать, что эта статья отнюдь не претендует на полные ибезоговорочные рекомендации по переходу от С к С++. Тут даны лишь некоторые изочень многочисленных и может быть наиболее распространенные из них. Итак, кделу…
Длятого чтобы освоиться с C++, необходимо некоторое время. Поскольку С является, посуществу, подмножеством C++, все его старые «трюки» остаются в силе, номногие из них теряют свою значимость. Так, например, для программистов на C++выражение «указатель на указатель» звучит немного забавно. Почемувместо указателя не была использована просто ссылка?
С- достаточно простой язык. Макросы, указатели, структуры, массивы и функции — этопочти все, что он в действительности предлагает. Каким бы сложным ни оказалсяалгоритм, его всегда можно реализовать, используя перечисленный набор средств.
ВC++ дело обстоит несколько иначе: наравне с макросами, указателями, структурами,массивами и функциями используются закрытые и защищенные члены классов, перегрузкафункций, аргументы по умолчанию, конструкторы и деструкторы. Операции, определяемыепользователем, встроенные функции, ссылки, дружественные классы и функции, шаблоны,исключения, пространства имен и т. д. Очевидно, что более богатые средствапроектирования предоставляют и более широкие возможности, а это в свою очередь,требует существенно иной культуры программирования.
Столкнувшисьс таким разнообразием выбора, многие теряются, продолжая крепко держаться за то,к чему они привыкли. По большей части в этом нет особого греха, но некоторые«привычки» из С идут вразрез с духом C++. От них просто необходимоизбавиться!
Давайтерассмотрим две наиболее частые и стойкие (на мой взгляд и собственный опыт)«привычки» из С — это использование директивы #define и функцийscanf/printf.
Предпочитайтеconst и inline использованию #define
Этотправило лучше было бы назвать «Компилятор предпочтительнеепрепроцессора», поскольку #define зачастую вообще не относят к языку C++.В этом и заключается одна из проблем. Рассмотрим простой пример; попробуйтенаписать что-нибудь вроде: #define ASPECT_RATIO 1.653
Символическоеобозначение может так и остаться неизвестным компилятору или быть удаленопрепроцессором, прежде чем код попадет в компилятор. Если это произойдет, тообозначение ASPECT_RATIO не окажется в таблице символов. Поэтому в ходекомпиляции вы получите ошибку, связанную с использованием константы (всообщении об ошибке будет сказано 1.653, а не ASPECT_RATIO).
Этовызовет путаницу. Если файл заголовков писали не вы, а кто-либо другой, у васне будет никакого представления о том, откуда взялось значение 1.653, и напоиски ответа вы потеряете много времени. Та же проблема может возникнуть и приотладке, поскольку обозначение, выбранное вами, будет отсутствовать в таблицесимволов.
Указаннаязадача решается просто и быстро. Вместо использования макроса препроцессораопределите константу: const double ASPECT_RATIO = 1.653;
Однакоесть два специальных случая, заслуживающих упоминания. Во-первых, приопределении константных указателей могут возникнуть некоторые осложнения.Поскольку определения констант обычно выносятся в заголовочные файлы (где к нимполучает доступ множество различных исходных файлов), важно, чтобы самуказатель был объявлен с const, в дополнение к объявлению const того, на что онуказывает. Например, для определения в файле заголовков константной строкиchar* следует писать const дважды: const char* const constantString =«String is constant»;
Во-вторых,иногда удобно определять некоторые константы, как относящиеся к конкретнымклассам, а это требует другого подхода. Для того чтобы ограничить областьдействия константы конкретным классом, необходимо сделать ее членом этогокласса, а чтобы гарантировать, что существует только одна копия константы, требуетсясделать ее статическим (static) членом класса:
class GamePlayer
{
private:
static const int NUM_TURNS = 5; // Объявление константы
intscores[NUM_TURNS]; // Использование константы
};
Остаетсяеще одна небольшая проблема, поскольку все то, что вы видите выше — этообъявление, а не определение NUM_TURNS. Если вам необходимо определитьстатические члены класса в файле реализации, то напишите следующее:
сonstint GamePlayer::NUM_TURNS; // Обязательное объявление
//находится в файле реализации
Впрочем,терять сон из-за подобных пустяков не стоит. Если об определении забудете вы, тонапомнит компоновщик.
Старыекомпиляторы могут не поддерживать принятый здесь синтаксис, так как в болееранних версиях языка было запрещено задавать значения статических членов классаво время их объявления. Более того, инициализация в классе допускалась толькодля целых типов (таких как int, bool, char и пр.) и для констант. Есливышеприведенный синтаксис не работает, то начальное значение следует задавать вопределении:
classEngineeringConstants // Это находится в файле заголовка класса.
{
private:
static const double FUDGE_FACTOR;
};
Аэто находится в файле реализации класса: const doubleEngineeringConstants::FUDGE_FACTOR = 1.35;
Единственноеисключение обнаруживается тогда, когда для компиляции класса необходимаконстанта. Например, при объявлении массива GamePlayer::scores в листинге, приведенномвыше, в момент компиляции может потребоваться задание его размера. Для тогочтобы работать с компилятором, ошибочно запрещающим инициализировать целыеконстанты внутри класса, следует применять технику, которая иногда называется«трюком с перечислением». Она основана на том, что переменныеперечисляемого типа можно использовать там, где ожидаются целые числа, поэтомуGamePlayer определяют следующим образом:
classGamePlayer
{
private:
enum{ NUM_TURNS = 5 }; //трюк с перечислением — делает из
//NUM_TURNSсимвол со значением 5
int scores[NUM_TURNS]; //теперь нормально
};
Есливы имеете дело не с примитивным компилятором, написанным до 1995 года ипредставляющим собой только исторический интерес, то считайте, что вам скореевсего повезло: необходимость использовать этот трюк вероятно отпадет самасобой. Вернемся к препроцессору. Другой частый случай неправильногоиспользования директивы #define — создание макросов, которые выглядят какфункции, но не обременены накладными расходами функционального вызова.Канонический пример — вычисление максимума двух значений: #define max(a, b)((a)>(b)?(а):(b))
Вэтой небольшой строчке содержится так много недостатков, что даже не совсемпонятно, с какого проще начать. Всякий раз, когда вы пишете макрос подобныйэтому, необходимо помнить, что все аргументы следует заключать в скобки. Впротивном случае у пользователей будут возникать серьезные проблемы сприменением таких макросов в выражениях. Но, даже если вы все сделаете верно, посмотрите,какие странные (если не сказать — страшные) вещи могут при этом произойти:
intа = 5, b = 0;
mах(++а,b); //здесь переменная «а» — увеличивается дважды
mах(++а,b+10); //а здесь — только 1 раз и это правильно
Происходящеевнутри mах зависит от того, что с чем сравнивается! Не верится? Проверьте сами.К счастью, вам нет нужды мириться с поведением, так сильно противоречащимпривычной логике. Существует метод, позволяющий добиться такой же эффективности,как при использовании макросов. В таком случае обеспечиваются какпредсказуемость поведения, так и контроль типов аргументов (что характерно дляобычных функций). Этот результат достигается применением встраиваемых функций:
inlineint max(int a, int b) { return a > b? a: b; }
Новаяверсия max несколько отличается от предыдущей, поскольку она может работатьтолько с целыми аргументами. Возникшую проблему удачно решает шаблон:
template
inlineconst Т& max(const Т& а, const T& b)
{return а > b? а: b; }
Онгенерирует целое семейство функций, каждая из которых берет два приводимых к одномутипу объекта и возвращает ссылку (с модификатором const) на больший из двухобъектов. Поскольку вам неизвестно, каким будет тип Т, для эффективностипередача и возврат значения происходят по ссылке.
Кстатиговоря, прежде чем вы решите писать шаблон для какой-либо функции, подобной max,узнайте, не присутствует ли она уже в стандартной библиотеке. В случае с max выможете воспользоваться плодами чужих усилий: max является частью стандартнойбиблиотеки C++.
Предпочитайтеиспользованию
Оэти операторы sсanf() и printf()! Практически все формы обучения языку С и(увы) С++ начинаются с них. Да, они переносимы. Да, они эффективны. Да, вы ужедаже знаете, как их нужно использовать. Но какой бы благоговейный восторг онини вызывали, факт остается фактом: операторы sсanf() и printf() и им подобныедалеки от совершенства. В частности, они не осуществляют контроль типапеременной и к тому же нерасширяемы.
Посколькуконтроль типов и расширяемость — краеугольные камни идеологии C++, то лучшевсего с самого начала во всем опираться на них. Кроме того, семейство функцийprintf/scanf отделяет переменные, которые необходимо прочитать или записать, отформатирующей информации, управляющей записью и чтением. Неудивительно, что этислабости функции printf/scanf — сила операторов " и ".
inti;
Rationalr; // r является рациональным числом (класс Rational).
cin " i " r;
cout " i " r;
Еслиэтот код предназначен для компиляции, должны быть в наличии функцииoperator" и operator", которые могли бы работать с объектом типа Rational.Отсутствие данных функций является ошибкой. (Для int и других стандартных типовимеются стандартные версии этих операторов.)
Болеетого, компилятор берет на себя заботу о том, какие версии операторов вызыватьдля разных переменных. Таким образом, вам нет необходимости беспокоиться о том,что первый читаемый или записываемый объект имеет тип int, а второй — Rational- с этим разберется компилятор!
Крометого, считывание объектов происходит с использованием той же синтаксическойформы, что и при записи. Поэтому нет необходимости помнить о том, что, если выработаете не с указателем, важно не забыть взять адрес, а если имеете дело суказателем, следует убедиться, что вы не берете адрес. Пусть о таких деталяхзаботится компилятор C++. Это его дело. У вас же есть задачи посерьезнее.
Инаконец, заметьте, что встроенные типы, подобные int, читаются и записываютсясовершенно аналогично типам, определенным пользователями, таким, например, какRational. Попробуйте сделать то же самое, используя scanf/printf!
Нижеприводится пример того, как можно написать функцию для вывода классарациональных чисел:
class Rational
{
public:
Rational(int numerator=0, int denominator=1);
intn, d; //числитель и знаменатель
friend ostream& operator"(ostream& s, const Rational&r);
};
ostream& operator"(ostream& s, const Rational& r)
{
s " r.n " '/' " r.d;
return s;
}
Этаверсия operator" демонстрирует некоторые тонкости (притом весьма важные!).Например, она не является функцией-членом, а объект Rational передаетсяoperator" по ссылке const, а не как объект. Соответствующая функция ввода,operator", объявляется и реализуется аналогичным образом.
Какни обидно это признавать, в ряде случаев имеет смысл вернуться к старому ипроверенному способу. Во-первых, некоторые реализации операций потоковввода/вывода менее эффективны, чем соответствующие операции С, и возможно (хотямаловероятно), что в отдельных приложениях это может оказаться существенным.Помните, однако: это относится не к потокам ввода/вывода вообще, а только к тойили иной реализации. Во-вторых, библиотека потоков ввода/вывода, в ходе своейстандартизации претерпела ряд кардинальных изменений. Следовательно, приложения,требующие максимальной переносимости, могут столкнуться с тем фактом, чторазличные поставщики поддерживают различные приближения стандарта.
Инаконец, поскольку классы библиотеки потоков ввода/вывода имеют конструкторы, афункции — нет, в редких случаях существенным будет порядокинициализации статических объектов, и стандартная библиотека С окажется болееудобной просто потому, что вы можете ею пользоваться без опасений.
Контрольтипов и расширяемость, предлагаемые классами и функциями библиотеки потоковввода/вывода, являются более важными, чем это может показаться, — не стоитотвергать их только из-за того, что вы привыкли к .
Междупрочим, это не опечатка — в названии данного правила действительно фигурирует, а не . Строго говоря, такого заголовка, как, не существует: Комитет по стандартам отказался от него впользу названия при сокращении имен стандартных файловзаголовков, отсутствующих в библиотеке языка С.
Важноуяснить следующее: если (что весьма вероятно) ваш компилятор поддерживает какфайл заголовков , так и , необходимо иметь ввиду, что они слегка отличаются друг от друга. В частности, если вы включаете, элементы библиотеки потоков ввода/вывода весьма удобнорасположены в пространстве имен std; включая , вы получаетете же элементы, но в глобальном пространстве имен. Их определение в нем можетвести к конфликтам, предотвращению которых и должно было послужить введениепонятия пространства имен. Кроме того, короче, чем.
Длямногих это оказывается достаточным аргументом в пользу нового названия. Вот наэтом пока и все. Если будут вопросы — пишите. По результатам вашего любопытствамогут появиться новые статьи.
Принаписании данного текста активно использовалась книга Скотта Мейерса.
Списоклитературы
Scott Meyers Effective C++ Second Edition AWG 1998
Дляподготовки данной работы были использованы материалы с сайта my-pc.jino.ru/


Не сдавайте скачаную работу преподавателю!
Данный реферат Вы можете использовать для подготовки курсовых проектов.

Поделись с друзьями, за репост + 100 мильонов к студенческой карме :

Пишем реферат самостоятельно:
! Как писать рефераты
Практические рекомендации по написанию студенческих рефератов.
! План реферата Краткий список разделов, отражающий структура и порядок работы над будующим рефератом.
! Введение реферата Вводная часть работы, в которой отражается цель и обозначается список задач.
! Заключение реферата В заключении подводятся итоги, описывается была ли достигнута поставленная цель, каковы результаты.
! Оформление рефератов Методические рекомендации по грамотному оформлению работы по ГОСТ.

Читайте также:
Виды рефератов Какими бывают рефераты по своему назначению и структуре.

Сейчас смотрят :

Реферат Устранение конфликтов в трудовом коллективе
Реферат Векторы эволюции
Реферат Голсуорси Джон
Реферат The USA economy
Реферат Развитие навыка чтения и аккомпанирования с листа как фактор творческого и интеллектуального роста педагога-баяниста в общеобразовательном учреждении эстетического воспитания.
Реферат Детско-родительское общение
Реферат Геренук
Реферат Гайморит
Реферат Методичні засади формування в бухгалтерському обліку інформації про витрати виробництва визначені
Реферат Проблемы возрождения культурной памяти в решениях региональных научных конференций
Реферат Представление о психологическом консультировании, психологической коррекции и психотерапии
Реферат 3 розділ І теоретико-правові основи працевлаштування молоді
Реферат Восприятие учителями личностных качеств учащихся
Реферат 1. Двумя событиями, соответствующими периоду I мировой войны и нарастания общенационального кризиса в России, были
Реферат Проектирование пневмогидросистемы первой ступени баллистической ракеты