- •1.1. Что такое программа и как она выглядит?
- •1.2. Комментарии
- •1.3. Зарезервированные слова и типы данных
- •1.4. Объявление переменных
- •1.5. Операции и выражения
- •1.6. Ввод и вывод
- •1.7. Переменные и константы
- •1.8 Логические операторы
- •1.9. Управляющие операторы
- •1.10. Операторы циклов
- •1.11. Операторы перехода
- •2. Функции
- •2.1. Передача параметров
- •2.2. Библиотечные функции
- •2.3. Локальные и глобальные переменные
- •Объявления функций
- •Время жизни и область видимости программных объектов
- •Int local_var; /* по умолчанию auto */
- •2.4. Перегрузка
- •3. Массивы
- •4. Структуры
- •Int numberPeriod; //число переодов начисления процентов
- •Int page; //Количество страниц
- •Void print(); /*Внимание, записывается только прототип функции */
- •Int yearBorn; //год рождения
- •Int yearBorn; //год рождения
- •4.1. Демонстрационные программы
- •Int done;/*переменная, которая информирует о конце списка файлов */
- •6. Объединения
- •Info;//Обявление переменной типа объединение
- •Info;//Обявление переменной типа объединение
- •7. Объектно-ориентированное программирование
- •7.1. Классы и объекты
- •Демонстрационные программы
- •Результат работы программы
- •7.2. Конструкторы и деструкторы
- •Конструктор копирования
- •7.5. Наследование
- •7.3. Создание объектов и обращение к членам объекта
- •8. Абстрактные типы данных
- •9. Пространство имен
- •Void greeting();/*это пространство имен содержит функцию с тем же именем*/
- •Void big_greeting(); /*эта функция не попадает ни в одно из созданных подпространств,т.Е. Принадлежит пространству имен std */
- •//Определение функций
- •Void big_greeting() /* определение данной функции не принадлежит ни одному из созданных пространств имен, следовательно дальнейший код помещается в глобальное пространство имен */
- •10. Строки
- •4.3 Демонстрационные программы
- •4.10. Класс string
- •Класс AnsiString
- •Класс AnsiString
- •Класс Set
- •4.9. Перегрузка операторов
- •Использование "умных" указателей
- •4.8. Полиморфизм
- •Главное меню — компонент MainMenu
- •Диалоги
- •Файлы и потоки
- •Ввод-вывод в файл
- •Ifstream inStream; //Объявление входного потока
- •InStream.Open("character.Dat"); /*присоединение файла к входному потоку */
- •InStream.Close(); //закрытие входного потока
- •If(!out){ //при неудачной попытке
- •If(in.Fail()){ //поток не создан, то сообщение и выход
- •Управление потоком ввода-вывода
- •5.2. Ввод имен файлов
- •5.3. Манипуляторы
- •5. Указатели
- •5.1.Типы указателей и операции с указателями
- •Адресная арифметика
- •Сравнение указателей
- •Преобразование типа указателя
- •Указатель void
- •5.2. Динамические массивы
- •Int array[10]; //объявляется массив с именем array
- •Int a[10]; //объявляется массив с именем a
- •Int *array1; //указатель типа int с именем array1
- •Int *array[5];/*массив с именем array, его элементы указатели*/
- •Int (*point)[4][5]; /*объявление указателя на двумерный массив без имени */
- •Использование указателей в функциях и указатели на функции
- •Указатель классов
- •Шаблоны
- •Шаблоны функций
- •Void Swap (t& X, t& y) /* к моменту обращения тип т будет известен и заменен, например, на int */
- •Void sort(t array[], int maxIndex){ /*передали массив и его размер */
- •6.2. Шаблоны классов
- •6.3 Демонстрационные программы
- •7.1 Обработка исключений
- •Исключения и их стандартная обработка
- •Базовый класс исключений vcl Exception
- •Упражнения
- •Обработка исключительных ситуаций, возбуждаемых оператором new
- •Исходные файлы и объявление переменных
- •Связаные списки
- •Void newHead( //прототип функции создающей узел
- •Void newHead(//прототип функции создания узла
- •Поиск в связанных списках
- •Void newHead(PtrNode& head, //адрес головного узла
- •Директивы препроцессора.
- •Структура файла проекта
- •Структура make-файла
- •Структура модуля
- •Структура h-файла
- •Файл формы
- •Особенности программирования под Windows.
- •Функция WinMain
- •Создание проекта Win32Application.
- •Библиотека mfc.
- •Создаем код
- •Шпаргалка
- •Структура файла проекта
- •Структура make-файла
- •Структура модуля
- •Структура h-файла
- •Файл формы
- •Файл проекта
- •Введение
- •Свойства компонентов
- •События
- •Менеджер проектов
- •Пример: создание простейшего приложения
- •Графика Внедрение картинок
- •Редактор изображений
- •Классы для хранения графических объектов.
- •If (SelectDirectory( //Компонент библиотеки
- •Методы создания собственной графики. Рисование по пикселам
- •Int px, py; //координаты пикселей
- •Рисование с помощью пера
- •Int px, py; //координаты пикселей
- •Рисование кистью
- •Мультимедиа и анимация Общие сведения о звуковых и видеофайлах
- •Способы воспроизведения звуков
- •Создание мультфильма
- •Воспроизведение немых видео клипов — компонент Animate
- •Проигрыватель MediaPlayer
- •Процессы, потоки, распределенные приложения
- •If include "uOverlayl.H" // включение головного файла приложения
- •Функция CreateProcess
- •490 _ Глава 7
- •7.8.4 Элементы ActiveX
- •492 Глава 7
- •494 Глава 7
- •7.9 Компоненты-серверы сом
- •496 Глава 7
- •7.9.2 Свойства и методы сервера Word
- •500 Глава 7
- •Заключение
- •Что такое ansi?
- •Почему вместо русских букв в консольном приложении выводится мусор? Автор: Алексей Кирюшкин Версия текста: 1.0
- •Раздел I.2Выход 1
- •Раздел I.3Выход 2
- •Раздел I.4Выход 3
- •Раздел I.5Выход 4
- •(A)Потоки
- •(C)Ввод-вывод файлов
- •Выбор компонентов для групповых операций
- •Установка разделяемых свойств компонентов
- •Изменение размера компонентов
- •Выравнивание компонентов
- •Пример: Создание текстового редактора Проектирование формы приложения
- •Создание обработчиков событий
- •Создание меню
Упражнения
Введите, откомпилируйте и запустите предыдущие примеры программ. Затем поэкспериментируйте с ними, меняя фрагменты и исследуя результаты.
Что неправильно в данном фрагменте?
int main(){
throw 12.23;
. . .
3. Что неправильно в данном фрагменте?
try {
// ...
throw 'а';
catch(char *){
4. Что может произойти при возбуждении исключительной ситуации, для которой не задано соответствующей инструкции catch?
Обработка исключительных ситуаций, возбуждаемых оператором new
При неудачной попытке выделения памяти оператор new возбуждает исключительную ситуацию.
С момента появления языка C++ точное определение действий, которые должны выполняться при неудачной попытке выделения памяти с помощью оператора new, менялось несколько раз. После разработки языка при неудачной попытке выделения памяти оператор new возвращал нуль, несколькими годами позднее — возбуждал исключительную ситуацию. Кроме того, неоднократно менялось имя этой исключительной ситуации. В конце концов было решено, что неудачная попытка выделения памяти с помощью оператора new по умолчанию будет возбуждать исключительную ситуацию, но по желанию в качестве опции можно возвращать нулевой указатель. Таким образом, оператор new реализовывался по-разному в разное время разными производителями компиляторов. Хотя в будущем все компиляторы должны быть выполнены в точном соответствии с требованиями стандарта Standard C++, сегодня это не так. Все это сказано для того, что некоторые примеры приведенные ниже на некоторых компбютерах могут не работать.
В соответствии со стандартом Standard C++, когда требование на выделение памяти не может быть выполнено, оператор new возбуждает исключительную ситуацию bad_alloc. При невозможности перехватить эту исключительную ситуацию программа завершается. Хотя для коротких программ такой алгоритм кажется вполне очевидным и понятным, в реальных приложениях должны не только перехватить, но и каким-то разумным образом обратать эту исключительную ситуацию. Для доступа к указанной исключительной ситуации в программу необходимо включить заголовок <new>.
В представленном ниже примере с оператором new использование блока try/catch дает возможность проконтролировать неудачную попытку выделения памяти.
#include <iostream>
#include <windows>
#include <new>
using namespace std;
int main() {
SetConsoleOutputCP(1251);
int *p;
try {
p = new int; // выделение памяти для целого
} catch (bad_alloc xa) {
cout << "Ошибка выделения памяти\n";
return 1;
}
for(*p=0;*p<10;(*p)++)
cout<<*p<<" ";
delete p; // освобождение памяти
return 0;
}
В этом примере, если при выделении памяти случается ошибка, она перехватывается инструкцией catch. При работе в нормальных условиях ошибка выделения памяти чрезвычайно маловероятна, в представленном ниже примере ошибка выделения памяти достигается принудительно. Процесс выделения памяти длится до тех пор, пока не произойдет ошибка.
#include <iostream>
#include <windows>
#include <new>
using namespace std;
main(){
SetConsoleOutputCP(1251);
double *p;
// цикл будет продолжаться вплоть до исчерпания ресурса памяти
do {
try {
p = new double[100000]; } catch (bad_alloc xa) {
cout <<"Ошибка выделения памяти\n";
return 1;
}
cout << "Выделение памяти идет нормальнс\n";
} while(p);
return 0;
В качестве примера формирования исключений рассмотрим еще одну программу, которая находит наибольший общий делитель двух чисел x и y . Этот пример взят из [4]. Алгоритм программы прост. На каждом шаге выполняются сравнения:
если x==y, то ответ найден ;
если x<y, то y заменяется значением y-x;
если x>y, то x заменяется значением x-y.
//программа нахождения НОД
#include <iostream.h>
int GCM(int x, int y)
{try {if(x==0||y==0) throw "\nZERO!";
if(x<0) throw "\nNegativ parameter 1.";//
if(y<0) throw "\nNegativ parameter 2.";
while (x!=y)
{if(x>y) x=x-y;
else
y=y-x;
}
return x;
}
catch (const char *report)
{cerr<<report<<"x="<<x<<", y="<<y;
return 0;
}
}
void main()
{
cout<<"\nGCM(66,44)="<<GCM(66,44);
cout<<"\nGCM(0,7)="<< GCM(0,7);
cout<<"\nGCM(-12,8)="<< GCM(-12,8);
}
В заключение следует сказать, что программы, содержащие исключения следует запускать при помощи программ типа «проводника». Запуск из среды программирования может повлечь появление дополнительных сообщений отладчика (дебаггера) типа
.
Модули
Когда программист создает программу, то часто она выполняется в виде отдельных законченных кусков, которые связаны друг с другом. Например, в одном файле могут храниться классы созданные программистом. В другом функции объявленные в этих классах. В третьем вспомогательный код, обеспечивающий выход из программы в случае ее аварийного завершения. Наконец, есть головной файл в котором находится функция main. Если в программировании принимают участие несколько человек, то такое разделение является просто необходимым. Короче говоря, программа С++ почти всегда состоит из нескольких законченных, с точки зрения программирования, кусков или "модулей".
Модуль часто называют исходным файлом, иногда - единицей трансляции. Он состоит из описаний типов, переменных, констант и функций. Естественно, что между модулями должна существовать связь. В интегрированных средах программирования, каковыми явяляются Borland C++ Builder и Microsoft Visual C++ это делается достаточно просто. Все модули включаются в один проект. Компиляция проекта автоматически связывает модули, так, что обращение к элементам, находящимя в всоседем модуле выполняется так, как будто весь текст программы находится в одном файле.
Для того, чтобы понять как это выполнено в указанных средах рассмотрим пример в котором мы создадим три файла. В одном из них соберем все указания (директивы) препроцессора и прототипы функций. В другом, определим класс с двумя функциями, одна находит среднее арифметическое двух чисел вторая их средеее геометрическое. Наконец, файл, содержащий функцию main, которая осуществляет ввод данных и и вывод результатов.
Рассмотрим как это выполнить в виде 3-х файлов в среде Builder. В среде MS Visual C++ это делается аналогичным образом.
Сначала используя средства Windows создадим специальныю папку в которой будем сохранять проект. Затем создадим консольное приложение и запишем в нем головной файл, который назовем main. Такое имя вовсе не обязательно. Просто оно позволит лучше ориентироваться в файлах.
//головной файл main.cpp
#include”head.h”
int main(){
float x,y;
SetConsoleOutputCP(1251);
cout<<"Для вычисления среднего введите 2 числа"<<endl;
cout<<"x="; cin>>x;
cout<<"y="; cin>>y;
middl m(x,y);
cout<<"Среднее арифметическое="<<m.ma<<endl
<<"Сренее геометрическое="<<m.mg;
char z;
cin>>z;
return 0;
}
Сохраним его в созданной папке, как файл с именем main.cpp.
Теперь с помощью меню File|New|Other в открывшейся витрине файлов выберем CppFile. Запишем в него класс с объявлением, но без определения функций и сохраним в той же папке с именем class.cpp.
//файл с именем class.cpp
class middl{
private:
//Прототипы функций
float mar(float x, float y);// вычисление среденго арифметического
float mgeo(float x, float y);// для среднего геометрического
public:
float ma, mg;
middl(float x,float y){ //конструктор
ma=mar(x,y);
mg=mgeo(x,y);
}
~middl(){} //деструктор
};
Теперь вновь с помощью меню File|New|Other выберем HeaderFile.
//Файл head.h
#include <iostream>
#include<math>
#include<windows>
using namespace std;
#include “class.cpp”
float middl::mar(float x, float y){
return (x+y)/2;}
float middl::mgeo(float x, float y){
return sqrt(x*y);}
Сохраним его в той же папке с именеи head.h.
Теперь сохраним проект MyProjecr3Module в той самой папке с помощью пункта меню File|Save Project As… , и запустим, наконец, его на компиляцию.
После успешной компиляции появится файл MyProjecr3Module с расширением .exe. Это и есть тот файл, котрый готов к выполнению. Размер его сравнительно мал, менее 15,5 кБ. К слову говоря, объем памяти занимаемый одной страницей данного текста составляет более 25кБ.
Если программа отлажена и готова к исполнению, то все остальные файлы можно удалить. При этом нужно иметь в виду, что исходные коды всех модулей будут уничтожены. Это значит, что если вы надумаете внести какие то дополнения в код программы, то придется все делать заново.
Рассмотренный способ объединения файлов в проект вовсе не предусмотрен языком С++, а является следствием работы интегрированной системы, точнее следствием труда программистов которые ее создали. В языке С++ для создания многомодульных приложений применяется иной механизм. Для того, чтобы связаться из одного исходного файла с другим используется ключевое слово extern . Например, если необходима функция объявленная в соседнем файле, то в данном файле нужно объявить ее прототип.
extern {
int function1(arg1);
void function2(arg2,arg3);
}
В некоторых компиляторах разработанных в последнее время слово extern используется со строкой "С", например, код
extern "C"{
int function1(arg1);
void function2(arg2,arg3);
}
Данный пример говорит о том, что далее потребуются две функции которые находятся в каком-то другом месте. Это другое место может находится в том же модуле, но ниже, или в другом модуле.
В качестве примера сделаем следующее. Запишем в разные файлы две программы код которых приведен ниже. В первом файле с помощью функции Factorial вычисляется величина 7!. Во втором описывается сама функция Factorial. Первый файл содержит функцию main() из которой вызывается функция Factorial второго файла. В соответствии с правилами языка С++, перед вызовом функции должен быть описан хотя бы ее прототип, что сделано с помощью оператора extern. Обратите внимание, что используемая в программе переменная также описана в другом модуле.
//файл с именем extern1.cpp
#include <iostream>
using namespace std;
extern unsigned long factorial; /*объявление переменной factorial
*осуществлено в другом модуле*/
extern unsigned long Factorial (unsigned long); /*описание
*функции Factorial выполнено в другом модуле*/
void main()
{
factorial=Factorial(7);
cout<<"7!(factorial):"<<factorial<<endl;
// cin>> factorial;
}
//файл с именем extern2.cpp
unsigned long factorial; //объявление переменной factorial
unsigned long Factorial(unsigned long num)
{
return num>2?num*Factorial(num-1):num; /*Это оператор if записанный в такой форме. Если условие выполняется, то выполняется то, что записано после вопросительного знака (в данном случае рекурсивная функция) в противном случае выполняется то, что записано после двоеточия*/
}
Если вы работаете только с компилятором, то нужно откомпилировать сразу оба файла в командной строке. Для этого нужно указать имя файла содержащего компилятор и имена компилируемых файлов. В качестве такого компилятора возьмем компилятор “Borland C++ Builder”, от расположен в Borland/Cbuilder6/Bin/Bcc32.exe. Тогда это выгдядит так: bcc32.exe extern1.cpp extern2.cpp. После нажатия на клавиатуре кнопки Enter в директории с компилированными файлами сформируются еще 4 файла
extern1.exe
extern1.obj
extern1.tds
extern2.obj
Запустим extern1.exe. В результате получим:
7!(factorial):5040
Приведем небольшой законченный пример, в котором строка определяется в одном файле, а печатается в другом. Идея этого примера заимствована из книги Бьерна Страуструпа «Язык программирования С++». В примере созданы три файла header.h, main.cpp и f.cpp . В файле header.h определяются нужные типы, он состоит только из объявлений:
// header.h – это название файла
extern char * prog_name; //ссылка на указатель
extern void f (); //объявление прототипа функции f()
//Как ни странно на этом файл закончился
Еще раз напомним, что созданный файл состоит только из объявлений.
Файл main.cpp является основной программой:
// main.cpp – это название второго файла
#include "header.h" /*подключение файла с именем header.h
* хранящемся в той же директории */
char * prog_name = "примитивный, но законченный пример";
int main ()
{
f (); /* вызов функции f(). Компилятор поймет,
* что искать ее нужно в заголовочном файле*/
}
а строка печатается функцией из файла f.cpp:
// f.cpp – это имя третьего файла
#include <iostream.h>
#include "header.h"
#include <windows.h>
void f ()
{SetConsoleOutputCP(1251);
cout << prog_name << '\n';
}
После того как будут совместно откомпилированы все файлы исполняемая программа даст следующий результат:
Использование слова extern в такой, можно сказать традиционной манере, несколько устарело. Самый распространенный способ обеспечить согласованность описаний внешних во всех исходных файлах - поместить такие описания в заголовочные файлы. Заголовочные файлы можно включать во все исходные файлы, в которых требуются описания внешних файлов. Например, описание функции sqrt хранится в заголовочном файле стандартных математических функций с именем math, поэтому, если нужно извлечь квадратный корень из 4, можно написать:
#include <math>
using namespace std
//...
x = sqrt(4);
В команде включения заключенное в угловые скобки имя файла (в нашем примере - <math>) ссылается на файл, находящийся в стандартном пространстве имен. Файлы, находящиеся в других пространствах имен, вызываются также, но при этом нужно указать какому пространству имен они принадлежат.
Отвлечемся на некоторое время от пространств имен. Вспомним о том, что не все компиляторы поддерживают директиву using. Как же быть если нам попался именно такой компилятор? Ничего страшного в этом нет. Все действия по созданию заголовочных файлов довольно схожи, только в этом случае нужно указывать библиотечные файлы вместе с их расширением. Например:
#include <math.h>
//...
x = sqrt(4);
В команде включения заключенное в угловые скобки имя файла (в нашем примере - <math.h>) ссылается на файл, находящийся в стандартном каталоге включаемых файлов. В среде «Borland Builder 6» это каталог Borland\CBuilder6\Include. Файлы, находящиеся в других каталогах, обозначаются своими путевыми именами, взятыми в кавычки. Поэтому в следующих командах:
#include "math1.h"
#include "D:\ Borland\CBuilder6\Projects\math2.h"
включаются файл math1.h из текущего каталога пользователя и файл math2.h из каталога D:\ Borland\CBuilder6\Projects\.