Переопределение функций-членов внутри производного класса. — КиберПедия 

Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...

Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...

Переопределение функций-членов внутри производного класса.

2022-10-10 28
Переопределение функций-членов внутри производного класса. 0.00 из 5.00 0 оценок
Заказать работу

В языке С++ в производном классе разрешается переопределять функции-члены базового класса. В этом случае переопределение функции в производном классе заменяет ее реализацию в базовом классе.

Если в производном классе определяется функция-член с тем же типом возвращаемого значения и сигнатурой, как и у функции-члена базового класса, но которая имеет другое содержимое – “тело”, то эта функция считается переопределенной.

 

1. #include<iostream>

2. usingnamespace std;

 

3. class avto {

4. public:

5. avto(): cena(35700), rashod(17.5), name("FIAT") {};

6. avto(int cena1): rashod(16.5), name("VOLVO"){cena=cena1;};

 

7. int GetCena() { return cena; }

8. char* GetName() { return name; }

9. double GetRashod() { return rashod; }

 

10. void OutPut() { cout <<"CENA="<< cena << endl <<

11.                     "MARKA="<< name << endl <<

12.              "RASHOD="<< rashod << endl; }

13. protected:

14. char* name;

15. int cena;

16. double rashod;

17. };

 

18. class gruz_avto: public avto {

19. public:

20. gruz_avto(): avto() { name="KamAZ"; grpodemn=20.5; };

21.   gruz_avto(double grp): avto(38900) { name="MAZ";

22.                         grpodemn=grp; };

   

23. void OutPut() { cout <<"CENA="<< cena << endl <<

24.                      "MARKA="<< name << endl <<

25.          "RASHOD="<< rashod << endl <<

26.          "GRUZOPODEMN="<< grpodemn << endl; }  

27. private:

28. double grpodemn;

29. };

 

Int main()

31. { avto A; A.OutPut(); cout <<" aaaaa\n"<< endl;

32. avto B(33450); B.OutPut(); cout <<" bbbbb\n"<< endl;

   

33. gruz_avto C; C.OutPut(); cout <<" ccccc\n"<< endl;

34. gruz_avto D(23.5); D.OutPut(); cout <<" ddddd\n"<< endl;

 

35. return 0;

36. }

 

Вариант метода OutPut () определен (см. 10-12 строки) и внутри класса gruz _ avto (см. 23-26 строки).

В начале функции main () определяются объекты A (см. 31 строку) и B (см. 32 строку) класса avto, а затем вызывается соответствующий вариант метода OutPut ().

Ниже в тексте функции main () определяются объекты С и D класса gruz _ avto, и дважды вызывается уже другой вариант метода OutPut ().

Отметим, что внутри класса gruz _ avto можно метод OutPut () определить и следующим образом (вместо строк 23-26):

void OutPut() {avto::OutPut();

  cout <<"GRUZOPODEMN="<< grpodemn << endl;}

27 Виртуальные функции в языке С++.

Обсуждая реализацию механизма наследования в языке С++ в начале лекции мы определили два класса ­– avto (базовый класс) и gruz _ avto (производный от базового класс). При этом подразумевалось, что объекты класса gruz _ avto наследуют все поля и методы базового класса.

 

Перегруженная функция-член вызывается на основе использования алгоритма соответствия сигнатуре. При этом на этапе компиляции выбирается нужный вариант члена-функции. Использование виртуальных функций-членов класса позволяет выбирать динамически соответствующий вариант реализации функции-члена среди методов базового и производного классов.

 

Ключевое слово virtual играет роль спецификатора функции и обеспечивает упомянутый механизм. Сочетание виртуальных методов и открытого наследования наиболее полно обеспечивает полиморфизм.

 

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

 

Указатель на базовый класс может указывать либо на объект базового класса, либо на объект производного класса (ниже в примере смотри стр. 37). Выбор функции-члена будет зависеть от класса объекта, на который фактически во время выполнения программы указывает указатель.

 

!!! Различие в механизме выбора замещенной виртуальной функции и выбором перегружаемой функции заключается в том, что перегружаемая функция выбирается на этапе компиляции, и они (перегружаемые функции) могут иметь различные типы возвращаемых значений. Виртуальная же функция выбирается на этапе выполнения на основе объекта, который передается ей в качестве аргумента-указателя this. Кроме того, будучи однажды объявленной как виртуальная, функция сохраняет это свойство во всех переопределениях в производных классах.

 

1. #include<iostream>

2. usingnamespace std;

 

3. class avto {

4. public:

5. avto(): cena(15700), rashod(7.5) { name="Ford";

6.         cout <<"Class AVTO!!!"<< endl;};

 

7. ~avto() { cout <<"Object AVTO-class DESTROY!"<< endl; };

 

8. void SetCena(int cena) { (*this).cena=cena; }

9. void SetRashod(double rashod) { this->rashod=rashod; }

10. int GetCena() { return cena; }

11. char* GetName() { return name; }

12. double GetRashod() { return rashod; }

 

13. virtualvoid OutPut() { cout << GetCena() << endl <<

14.            GetName() << endl << GetRashod() << endl; }

 

15. protected:

16.         char* name;

17.    int cena;

18.    double rashod;

19. };

 

20. class gruz_avto: public avto {

21. public:

22. gruz_avto(): grpodemn(10.5) { cena=25000; rashod=18.5;

23.    name="MAZ"; cout <<"Class GRUZ_AVTO!!!"<< endl;};

 

24. ~gruz_avto() {cout <<"Object GRUZ_AVTO-class DESTROY!"

25.          << endl;};

 

26.  void SetGruzopodemnost(double grpodemn)

27.              { this->grpodemn=grpodemn;}

28. double GetGruzopodemnost() {return grpodemn;}

 

29.   void OutPut() { cout << GetCena() << endl <<

30.               GetName() << endl << GetRashod() <<

31.                endl << grpodemn << endl; }

 

32. private:

33. double grpodemn;

34. };

 

35. int main()

36. { avto A; A.OutPut();

37. avto* B = new gruz_avto; B->OutPut(); delete B;

38. gruz_avto C; C.OutPut();

39.return 0;

40. }

 

 

Внутри базового класса avto определен (см. 13-14 строки) виртуальный метод OutPut (). Вариант метода OutPut () определен (см. 29-31 строки) и внутри класса gruz _ avto.

 

В начале функции main () определяется объект A (см. 36 строку) класса avto, а затем вызывается соответствующий вариант метода OutPut ().

 

Ниже в тексте функции main () определяется указатель B на класс avto, но при этом используется вызов явного конструктора класса gruz _ avto, что разрешается в языке С++. При удалении соответствующего объекта будет использоваться только деструктор класса avto.

 

Далее определяется объект С класса gruz _ avto, и вызывается соответствующий вариант метода OutPut ().

 

28 Перегрузка операторов в языке С++. Общие понятия.

Ранее мы познакомились с механизмом перегрузки функций, когда имеется возможность определять несколько функций, имеющих одно и то же имя при условии, что у них разные сигнатуры (списки аргументов). На основе перегрузки функций в языке С++ реализуется функциональный полиморфизм.

В языке С++ реализован механизм перегрузки операторов. Такая перегрузка представляет собой еще один пример полиморфизма. Перегрузка операторов предоставляет возможность рассматривать операторы языка C++ сразу в нескольких смыслах. Фактически часть операторов языка C++ уже перегружены изначально. Например, оператор *, будучи примененной к адресу, дает значение, которое хранится по этому адресу. Однако, применяя оператор * к паре числовых значений, получаем произведение этих значений. Таким образом, в данном случае в языке C++ используется количество и типы операндов, чтобы решить, какое действие предпринять.

В отличие от функций для операторов языка С++ предусматриваются два дополнительных свойства, существенным образом влияющих на их функциональность: приоритет и ассоциативность. Действительно, встает вопрос как при записи понимать: a+b*c – как (a+b)*c или как a+(b*c)? Выражение a-b+c — это (a-b)+c или a-(b+c)?).

Приоритет (ранг или старшинство оператора) — формальное свойство оператора, влияющее на очередность его выполнения в выражении с несколькими различными операторами при отсутствии явного (с помощью скобок) указания на порядок их вычисления. Например, оператор умножения * обладает изначально более высоким приоритетом, чем оператор сложения +, а потому в выражении a + b * c будет получено сначала произведение b и c, а потом уже сумма.

Операторы могут иметь одинаковый приоритет, тогда они вычисляются по правилу ассоциативности, установленному для них. В программировании ассоциативностью операторов называют последовательность (очередность) их выполнения в случае, когда операторы имеют одинаковый приоритет и отсутствует явное (с помощью скобок) указание на очерёдность их выполнения. Причем различается левая ассоциативность, при которой вычисление выражения происходит слева–направо, и правая ассоциативностьсправа–налево. Соответствующие операторы называют левоассоциативными и правоассоциативными. Например, в языке xBase СУБД VisualFoxPro большинство операторов имеет левую ассоциативность, в то время как возведение в степень правоассоциативно: x 2 записывается по правилам xBase в виде x **2 или x ^2.

В языках программирования (в том числе в языке С++) применяются два способа задания приоритетов операторов:

· Первый из них связан с распределением всех операторов по иерархии приоритетов. Этот способ всегда используется для задания приоритетов по умолчанию и фиксируется в описании языка в виде соглашения, что соответствующим операторам присваивается определенные приоритеты.

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

Поскольку для встроенных в язык операторов всегда предусматриваются приоритеты и ассоциативность, то возникает вопрос: какие приоритеты и ассоциативность будут иметь переопределённые версии этих операторов или, тем более, новые созданные программистом операторы?

Кроме того, имеются и другие “тонкие моменты”, которые могут требовать уточнения. Например, в языке С++ существуют две формы операторов инкремента (увеличения) и декремента (уменьшения) значения ++ и -- — префиксная и постфиксная, поведение которых различается. Как должны вести себя перегруженные версии таких операций? Различные языки по-разному решают приведённые вопросы. Так, в языке C++ приоритет и ассоциативность перегруженных версий операторов сохраняются такими же, как и у определённых в языке, а описания перегрузки префиксной и постфиксной формы операторов инкремента и декремента используют различные сигнатуры.

Итак!!! Перегрузка операторов — это возможность назначать новый смысл операторам при использовании их с определенным классом.

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

· Чтобы перегрузить оператор, необходимо определить класс, которому оператор будет назначен;

· Когда перегружаете оператор, то перегрузка действует только для класса, в котором он определяется. Если программа использует оператор с неклассовыми переменными (например, переменными типа int или float), используется стандартное определение оператора;

· Чтобы перегрузить оператор класса, необходимо использовать ключевое слово языка C++ operator для определения метода класса, который вызывается каждый раз, когда переменная класса использует оператор;

· В языке С++ разрешается перегружать следующие операторы:

+ - * / % ^ & | ~!

= <> += -= *= /= %= ^= &=

|= <<>>>>= <<= ==!= <= >= &&

|| ++ -- ->*, -> [] () newdelete

· C++ не позволяет вашим программам перегружать оператор выбора элемента (.), оператор указателя на элемент (.*), оператор разрешения области видимости (::), условный оператор сравнения (?:), оператор sizeof().

 

 

29 Пример перегрузки унарных и бинарных операторов в языке С++.

Рассмотрим пример программы, в которой демонстрируется механизм перегрузки операторов. В программе определяется класс int_Matrix для организации обработки целочисленной матрицы. Внутри этого класса реализован явный конструктор, которым предусматривается генерация значений матрицы в диапазоне от 0 до 9 с помощью ГСЗ. Определен метод OutPut() для вывода матрицы на экран. В классе реализована перегрузка бинарных операторов – и +, а также перегрузка унарного оператора –.

1. #include<iostream>

2. #include<stdlib.h>

3. #include<time.h>

4. usingnamespace std;

5. class int _ Matrix // класс для обработки целочисленной матрицы

6. { public:

7. int_Matrix(int, int, int, int); // прототипконструктора

8. voidOutPut(int, int); // прототип метода вывода матрицы //прототип бинарного оператора - (вычитания)  

10. int_Matrixoperator - (int_Matrix&F);

11. //прототип бинарного оператора + (сложения)

12. int_Matrixoperator + (int_Matrix&D);

13. // прототип унарного оператора -

14. voidoperator - ();   

15. private:

16. enum {n=10, m=12};

17. int int_Matr[n][m]; // поле для размещения матрицы

18. };

 

19. // определениеконструктора

20. int_Matrix::int_Matrix(int n, int m, int min, int max)

21. { for(int i=0; i<n; i++)

22. for(int j=0; j<m; j++)

23.   int_Matr[i][j]=rand()%(max-min+1)+min;}

 

24. // определениеметода OutPut()

25. void int_Matrix::OutPut(int n, int m)

26. { for(int i=0; i<n; i++) {

27. for(int j=0; j<m; j++) cout << int_Matr[i][j] <<' '; 28.              cout << endl; } }

 

29. // определениебинарногооператора -

30. int_Matrix int_Matrix::operator - (int_Matrix& F)

31. { for(int i=0; i<n; i++)

32. for(int j=0; j<m; j++)

33.   F.int_Matr[i][j]=int_Matr[i][j]-F.int_Matr[i][j];

34. returnF; }

 

35. // определение бинарного оператора +

36. int_Matrix int_Matrix::operator + (int_Matrix& D)

37. { for(int i=0; i<n; i++)

38. for(int j=0; j<m; j++)

39. D.int_Matr[i][j]=int_Matr[i][j]+D.int_Matr[i][j];

40. returnD; }

 

41. // определение унарного оператора -

42. void int_Matrix::operator - ()  

43. { for(int i=0; i<n; i++)

44. for(int j=0; j<m; j++) int_Matr[i][j]=-int_Matr[i][j]; }

 

Int main()

46. { int n, m, min=0, max=9;

47. srand((unsigned)time(NULL));

48. cout <<"Vvedite kol-vo strok (<=10) i stolbtsov (<=12): ";

49. cin >> n >> m;

   

50. cout <<"\nMatritsa A:";

51. int_Matrix A(n,m,min,max); cout << endl; A.OutPut(n,m);

52. cout <<"\nMatritsa B:";

53. int_Matrix B(n,m,min,max); cout << endl; B.OutPut(n,m);

54. int_Matrix C(n,m,min,max);

55. C=B; cout <<"\nMatritsa A-B:\n"; C=A-C; C.OutPut(n,m);

56. C=B; cout <<"\nMatritsa A+B:\n"; C=A+C; C.OutPut(n,m);

57. cout <<"\nMatritsa -B:\n"; -B; B.OutPut(n,m);

58. return 0;

59. }

 

В строках с 5 по 18 включительно представлено определение класса int_Matrix для организации обработки целочисленной матрицы.

В строках с 29 по 34 и строках с 35 по 40 определены соответственно бинарные операторы – и +. Например, на вход оператора + (см. стр. 35) подается объект D класса int_Matrix. На основе вложенных циклов реализована операция поэлементного сложения матриц объекта D и объекта, стоящего в выражении сложения слева от +. В результате формируется матрица объекта D, которая и возвращается в качестве результата.

В строках с 42 по 44 определен унарный оператор –. На основе вложенных циклов реализована операция поэлементного отрицания значений элементов матрицы, для которой выполняется эта унарная операция.

Функция main () определена в строках с 45 по 59 включительно. В начале определяются переменные n и m для размещения в них значений числа соответственно строк и столбцов матрицы. Переменные min и max используются для определения границ диапазона, в котором случайным образом формируются значения элементов матриц A, B, C. Отметим, что матрица C используется как промежуточная для корректного выполнения операций A + B, A – B.

В строке 51 создается объект А, внутри которого с помощью ГСЗ формируется матрица целочисленных значений и ее значения выводятся на экран методом OutPut ().

В строке 53 создается объект B, внутри которого с помощью ГСЗ формируется матрица целочисленных значений и ее значения выводятся на экран методом OutPut (). В строке 54 создается объект C, внутри которого с помощью ГСЗ формируется матрица целочисленных значений.

В строках 55 и 56 соответственно реализованы операции A – B и A + B, причем матрица C играет важную роль, поскольку в процессе реализации указанных операций необходимо, с одной стороны, сохранить исходные значения матриц A и B, с другой стороны, формировать промежуточные результаты.

 

 

30 Основные правила перегрузки операторов в языке С++.

1) Нельзя вводить собственные обозначения для операторов, не совпадающие со стандартными операторами языка С++.

2) Не все операторы языка С++ могут быть перегружены. Так нельзя перегрузить:

. – прямой выбор элемента

.* – обращение к элементу через указатель на него

?: – условная операция

:: – операция указания области видимости

sizeof, # и ## – препроцессорные операции.

3) Каждый оператор в языке имеет определенное число операндов, свой приоритет и ассоциативность. Все эти правила сохраняются и при перегрузке, а изменить их нельзя.

4) Любой унарный оператор OP определяется двумя способами: либо как компонентная функция без параметров, либо как глобальная (возможно дружественная) функция с одним параметром. Выражение OP z означает в первом случае вызов z. operator OP (), во втором - вызов operator OP (z).

5) Любой бинарный оператор OP определяется также двумя способами: либо как компонентная функция с одним параметром, либо как глобальная (возможно дружественная) функция с двумя параметрами. В первом случае x OP y означает вызов x. operator OP (y), во втором – вызов operator OP (x, y).

6) Перегруженный оператор не может иметь аргументы по умолчанию.

7) В языке С++ установлена идентичность некоторых операторов, например, ++z – это тоже, что и z += 1. Эта идентичность теряется для перегруженных операторов.

8) Функцию operator можно вызвать по ее имени, например, z = operator * (x, y) или z = x. operator *(y). В первом случае вызывается глобальная функция, во втором – компонентная функция класса X, и x – это объект класса X. Однако, чаще всего функция operator вызывается косвенно, например, z = x * y.

 

31 Понятие потоков в языке С++.

Для обмена данными между программой и внешними устройствами в языках программирования предусматриваются операции ввода-вывода. Типичным внешним устройством ввода-вывода является консоль, представляющая собой комплект устройств (дисплей, клавиатура, мышь), присоединённых к компьютеру непосредственно, а не через сеть. На консоль можно вывести информацию, можно ввести информацию с клавиатуры или мыши.

 

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

 

В языке C++ нет специальных операторов для выполнения операций ввода или вывода данных. Вместо этого имеется стандартная библиотека < iostream >, стандартно поставляемая вместе с компилятором, c помощью классов которой и реализуются основные операции ввода-вывода (I / O – InputandOutput). Такой подход обеспечил эффект “ независимости от платформы ”.

 

Механизм для обеспечения выполнения операций ввода-вывода в С++ называется потоком. Название произошло оттого, что данные вводятся и выводятся в виде потока байтов.

 

Операции “ запись данных на внешнее устройство (диск) ” и “ считывание их с внешнего устройства (диска) ” являются относительно медленными, а потому могут существенно притормаживать выполнение программы. Для повышения скорости обмена данными предусматривается механизм буферизации. В этом случае данные сначала записываются в буфер потока, а после его наполнения все содержимое записывается на диск.

 

Реализация потоков и буферов в языке С++ построена на объектно-ориентированном подходе:

ü класс streambuf управляет буфером (с помощью соответствующих методов буфер может, например, наполняться, очищаться, сбрасываться).

ü класс ios является базовым для классов потоков ввода/вывода и внутри него в качестве переменной-члена предусмотрен объект streambuf.

ü классы istream и ostream являются производными от класса ios и используются, соответственно, для обеспечения потокового ввода и вывода данных.

ü класс iostream является производным от классов istream и ostream и используется для обеспечения ввода с клавиатуры и вывода на экран.

ü класс fstream используются для операций ввода и вывода из файлов.

 

Классы библиотеки < iostream > рассматривают данные, выводимые на экран, как побитовый поток данных. Когда данные выводятся (записываются) в файл или на экран дисплея, то источник потока содержится в программе. Если же поток вводится в программу из внешних источников, то данные могут поступать с клавиатуры или файла на диске, и они заносятся в переменные.

 

Класс istream реализует поток ввода, класс ostream – поток вывода. Эти классы определены в библиотеке < iostream >. Библиотека потоков ввода-вывода определяет три глобальных объекта: c in, c out, и cerr. Объект cin отвечает за ввод данных, объект cout является стандартным выводом, а cerr является потоком сообщений об ошибках. Объекты cout и cerr являются экземплярами класса ostream, а cin – объект класса istream.

 

 

32 Ввод данных с помощью объекта cin в языке С++.

Ввод данных с помощью объекта cin может осуществляться с использованием оператора >>. Например, для ввода целочисленного значения с клавиатуры можно записать следующий программный фрагмент:

int n; cin >> n; …

Объект cin включает перегруженный оператор ввода >>, который записывает данные из буфера в локальную переменную n. Оператор ввода перегружен таким образом, что предусматривает ввод данных основных базовых типов, включая int&, short&, long&, double&, float&, char&, char*. Когда в программе компилятор встречает выражение cin >> …, то вызывается вариант оператора ввода, соответствующий типу переменной. Поскольку параметр передается как ссылка, то оператор ввода способен изменять исходную переменную.

Объект c in может принимать в качестве аргумента указатель на строку символов типа char *, а потому можно с его помощью вводить массив символов, т.е. строку. Рассмотрим фрагмент кода:

 … charSTROKA[9];

cout<< “Введите строку:”;

cin>>STROKA; …

Если ввести слово ЯЗЫК, то массив STROKA будет заполнен слева 5 символами: Я, З, Ы, К, \0. Если же попробовать ввести фразу ЯЗЫК С++, то окажется, что введены будут только символы, стоящие до пробела, т.к. пробел выступает в роли заданного по умолчанию разделителя строк.

Отметим, что в языке С++ кроме перегружаемого оператора >> объект c in имеет ряд встроенных методов (getline(), get() и др.), которые позволяют обеспечивать более строгий контроль при выполнении ввода данных.

 

Например, для ввода строки символов можно использовать метод getline(). Рассмотрим пример простой программы, в которой определяются два массива типа char и ввод фразы ЯЗЫК С++ осуществляется с использованием метода getline()и оператора >>.

 

#include<iostream>

usingnamespace std;

 

int main()

{ char STROKA_1[9], STROKA_2[9];

   

cout <<"Vvedite 1 stroku:"; cin.getline(STROKA_1,9);

cout <<"Vvedite 2 stroku:"; cin >> STROKA_2;

   

cout << endl <<"STROKA_1:"<< STROKA_1;

cout << endl <<"STROKA_2:"<< STROKA_2 << endl;

 

return 0;

}

 

Отметим, что использование метода getline()позволило ввести полностью всю фразу, тогда как оператор >> обеспечил только ввод части фразы до первого слева пробела.

 

!!! При последовательном комбинированном вызове методов get(), getline() и оператора >> необходимо следить за правильным использованием буфера ввода.

 

 

33. Вывод данных с помощью объекта cout в языке С++

Вывод данных с помощью объекта cout может осуществляться с использованием оператора <<. Причем этот объект позволяет осуществлять:

· форматирование выводимых данных;

· выравнивание столбцов;

· вывод числовых значений не только в десятичном, но в восьмеричном и шестнадцатеричном представлении.

По умолчанию ширина поля вывода устанавливается автоматически таким образом, чтобы вместить все символы из буфера вывода. Используя метод width () можно точно определять значение ширины только следующего поля вывода. Отметим, что объект cout по умолчанию заполняет пробелами пустые позиции поля, однако можно с помощью метода fill () установить другой символ заполнения.

#include <iostream>

usingnamespace std;

Int main()

{

cout <<"->"; cout << 123456 <<';'<< endl;

cout <<"->"; cout.width(9); cout << 789 <<';'<< endl;

cout <<"->"; cout.width(3); cout << 123456 <<';'<< endl;

cout <<"->"; cout << 123456 <<';'<< endl;

cout <<"->"; cout.width(9); cout.fill('*');

cout << 789 <<';'<< endl;

cout <<"->"; cout.width(19); cout << 123456 <<';'<< endl;

return 0;

}

В языке С++ предусмотрен набор манипуляторов для управления правилами выполнения операций вывода. Примером такого манипулятора является endl, которой вставляет символ новой строки и очищает буфер вывода. Отметим, что для использования части манипуляторов в программе необходимо предусматривать подключение файла < iomanip >.

Набор манипуляторов, не требующих включения iomanip:

Манипулятор Действие
flush Очищает буфер вывода
endl Вставляет символ новой строки и очищает буфер вывода
oct Устанавливает восьмеричное основание для выводимых чисел
dec Устанавливает десятичное основание для выводимых чисел
hex Устанавливает шестнадцатеричное основание для вывода чисел
left Выравнивает выводимое значение по левому краю поля
right Выравнивает выводимое значение по правому краю поля
showpos Добавляет знак + перед положительным десятичным числом
noshowpos Отменяет вывод + перед положительным десятичным числом
uppercase Отображает шестнадцатеричные и экспоненциальные значения в верхнем регистре
nouppercase Отображает шестнадцатеричные и экспоненциальные значения в нижнем регистре
scientific Отображает числа с плавающей запятой в экспоненциальном представлении
fixed Отображает числа с фиксированной запятой

 

1. #include<iostream>

2. usingnamespace std;

Int main()

4. {

5. cout << showpos << "10 -> 8: ";

6. cout << 123456 << '=' << oct << 123456 << ';' << endl;

7. cout << "8 -> 16: ";

8. cout << 123456 << '=' << hex << 123456 << ';' << endl;

9. cout << "16 -> 8: " << uppercase;

10. cout << 123456 << '=' << oct << 123456 << ";\n" << endl;

11. cout << "->"; cout.width(20); cout << 789 << ';' << endl;

12. cout << "->"; cout << left << 789 << ';' << dec << endl;

13. cout << "->"; cout.width(20);

14. cout << 789 << ';' << endl;

15. cout << "->" << noshowpos; cout.width(20);

16. cout << right << scientific << nouppercase << 789.3

<< ';' << endl;

17. cout << "->" << left << fixed << 3.4567e+2 << ';' << endl;

18. return 0;

19. }

 

В строке 5 модификатор showpos включает режим отображения знака + перед выводом положительных десятичных чисел, а потому при выводе числа 123456 перед ним появится + (см. 6 строку). Модификатор oct (см. 6 стр.) устанавливает восьмеричное основание для выводимых чисел, а hex – шестнадцатеричное основание (см. 8 стр.).

В строке 9 модификатор uppercase включает режим вывода, при котором латинские буквы в шестнадцатеричных числах и в числах с плавающей запятой будут прописными (большими).

В 11 строке устанавливается ширина поля вывода 20 (cout. width (20);) и далее десятичное число 789 выводится в виде восьмеричного 1425 с выравниванием по правому краю.

В 12 строке модификатором left устанавливается режим выравнивания по левому краю, а модификатор dec вызывает переход к десятичному основанию для вывода целых чисел.

В 15 строке модификатор noshowpos подавляет вывод знака + перед положительными числами.

В 16 строке модификатором right устанавливается режим выравнивания по правому краю, модификатор scientific включает режим вывода вещественных значений в формате с плавающей точкой, а nouppercase устанавливает вывод латинских букв в шестнадцатеричных числах и в числах с плавающей запятой будут строчными (малыми).

В 17 строке модификатор fixed определяет режим вывода вещественных значений с фиксированной точкой.

Набор манипуляторов, для которых требуется подключение iomanip:

Манипулятор Действие
setw() Устанавливает ширину поля вывода
setprecision() Точность вывода – количество цифр в дробной части
setfill() Определяет символ заполнения при выводе

 

#include <iostream>

#include <iomanip>

usingnamespace std;

Int main()

{

cout << showpos << setw(15) << setfill('*') << 12.12345

<<';'<< endl;

cout << noshowpos << scientific << uppercase << setfill(' ')

<< setw(15) << setprecision(4) << 12.12345 <<';'<< endl;

cout << setw(15) << left << fixed << 3.12345e+2 <<';'

<< endl;

return 0;

}

34 Файловые потоки в языке С++.

Под файлом подразумевается поименованная совокупность данных на внешнем носителе, например, на винчестере. Логически файл может рассматриваться как конечная последовательность байтов, а потому такие устройства, как дисплей, клавиатуру и принтер также можно рассматривать как частные случаи файлов.

По способу доступа файлы можно разделить на последовательные, чтение и запись в которых производятся с начала байт за байтом, и файлы с произвольным доступом, допускающие чтение и запись в указанную позицию.

В стандартной библиотеке < fstream > языка С++ предусмотрены три класса для работы с файлами:

· ifstream — класс входных файловых потоков;

· ofstream — класс выходных файловых потоков;

· fstream — класс двунаправленных файловых потоков.

 

Эти три класса являются производными от классов istream, ostream и iostream соответственно, поэтому они наследуют перегруженные операции << и >>, флаги форматирования, манипуляторы, методы.

 

При работе с файлами в программе могут выполняться следующие операции:

• создание потока;

• открытие потока и связывание его с файлом;

• ввод/вывод данных;

• удаление потока;

• закрытие файла.

 

Каждый класс файловых потоков содержит конструкторы, с помощью которых можно создавать объекты этих классов различными способами. 

 

Конструкторы без параметров (ifstream (); ofstream (); fstream ()) создают объект соответствующего класса, не связывая его с файлом.

 

Конструкторы с параметрами создают объект соответствующего класса, открывают файл с указанным именем name и связывают файл с объектом:

ifstream (const char* nате, int mode = ios::in):

ofstream (const char* name, int mode = ios::out | ios::trunc):

fstream (constchar * name, int mode = ios::in | ios::out):

 

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

enum open_mode

{

in = 0x01       // открыть для чтения

out = 0x02              // открыть для записи

арр = 0x08             // открыть для добавления в конец

binary = 0x80 // открыть в двоичном режиме

}

 

35 Основы работы с текстовыми файлами в языке С++.

Текстовый файл в общем случае содержит последовательность строк, каждая из которых завершается специальным символом – признаком конца строки. За последней строкой размещается специальный признак конца файла – e nd _ o f _ f ile.

Рассмотрим пример программы, в которой создается текстовый файл, имя которого вводится с клавиатуры. В этот файл записываются 9 строк, и он закрывается. Далее из созданного файла читаются строки и выводятся на экран дисплея.

1. #include<fstream>

2. #include<iostream>

3. usingnamespace std;

Int main()

5. { char FileName[20];

6. char X[10];

7. cout <<"Vvedite imya FILE: "; cin >> FileName;

8. ofstream F(FileName);

9. for (int i=0; i<3; i++)

10. { cout <<"Vvedite "<< i <<" stroku: "; cin >> X;

11. F << X << endl << i << endl << 1.0/(i+1) << endl; };

12. F.close();

13. cout << endl <<"FILE "<< FileName <<": \n";

14. ifstream P(FileName);

15. while (! P.eof())

16. {

17. P >> X;

18. cout << X << endl;

19. }

20. P.close();

21. return 0;

22. }

 

 

В строке 1 подключается библиотека < fstream >, внутри которой определены три класса ifstream


Поделиться с друзьями:

Биохимия спиртового брожения: Основу технологии получения пива составляет спиртовое брожение, - при котором сахар превращается...

История развития пистолетов-пулеметов: Предпосылкой для возникновения пистолетов-пулеметов послужила давняя тенденция тяготения винтовок...

Типы оградительных сооружений в морском порту: По расположению оградительных сооружений в плане различают волноломы, обе оконечности...

История создания датчика движения: Первый прибор для обнаружения движения был изобретен немецким физиком Генрихом Герцем...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.015 с.