C ++ учебник для пользователей C

Этот текст показывает и освещается особенности и основные принципы C ++. Он нацелен на опытных пользователей C , которые хотят узнать C ++. Вы сможете выразить свой код, используя богатый синтаксис C ++ , и вы сможете прочитать некоторые код C++.

Хотя понятие вводится и сделано пригодными для использования, это не учебник о объектно-ориентированного программирования. Вы все еще должны узнать сущность ООП и детали ее реализации в C ++, для того, чтобы быть истинным C ++ программистом.

Если вы не имеете компилятор C ++ под рукой, может вам стоит использовать онлайн – инструменты , как этот: http://codepad.org

  1. Новый способ включить библиотеки
  2. //Для однострочных комментариев
  3. Консольного ввода и вывода потоков
  4. Объявления переменных могут быть помещены внутри кода без использования крючков
  5. Переменные могут быть инициализированы с помощью расчета с участием других переменных
  6. Переменные могут быть объявлены внутри декларации for loop
  7. Глобальные переменные могут быть доступны, даже если локальные переменные имеют одинаковые имена
  8. Можно объявить ССЫЛКУ на другую переменную
  9. Namespaces могут быть объявлены
  10. Функция может быть объявленакак inline
  11. Структура исключение добавлено
  12. Функция может иметь параметры по умолчанию
  13. FUNCTION OVERLOAD: несколько функций могут быть объявлены с тем же именем, при условии, что будет разница в их список параметров
  14. Символические операторы (+ – * /…) могут быть определены для новых типов данных
  15. Разные функции для разных типов данных будет создаваться автоматически, при условии, что вы определите функцию шаблона (template)
  16. Ключевые словаnewи delete гораздо лучше выделяют и освобождают памяти
  17. Вы можете добавить МЕТОДЫ К классу или структуре
  18. CONSTRUCTOR и DESTRUCTOR могут быть использованы для инициализации и уничтожения экземпляра класса
  19. Сложные классы нужны COPY CONSTRUCTOR и перегрузка=оператора
  20. Методы в body могут быть определены ниже определения класса (и Makefile пример использования)
  21. Ключевое словоthisявляется указателем на instance действующего метода
  22. Массивы экземпляров могут быть объявлены
  23. Пример полной декларации класса
  24. staticпеременные внутри определения класса
  25. constпеременные внутри определения класса
  26. Класс может быть получен из другого класса
  27. Если метод объявлен, виртуальная программа будет всегда проверить Тип экземпляра, на который указывает и использывает соответствующий метод.
  28. Класс может быть получен из более чем одного базового класса
  29. Наследование классов позволяет создавать общие методы
  30. Инкапсуляция: public, protected и private
  31. Краткие примеры файлов I/O
  32. Символьные массивы могут быть использованы как файлы
  33. Пример форматированного вывода

    1.

    Существует новый способ#include библиотеки (старый метод все еще работает, но компилятор жалуется). .h расширение больше не используется, а также имена стандартных библиотек C начиная с C . Для того, чтобы в программы  использовался эти библиотеки, using namespace std правильно должно быть добавлено:

using namespace std;
#include <iostream>

    // Это библиотека является ключевым C ++
#
include <

    cmath>

    // Стандартная библиотека C math.h

int main ()
{
double a;

a = 1.2;
a = sin (a);

cout << a << endl;

return 0;
}

 

 

Вывод
0.932039

 

 

Несколько советов для начинающих:

Для компиляции этой программы, введите его (или скопировать и вставить его) в текстовый редактор (gedit, kwrite, kate, kedit, vi, emacs, nano, pico, mcedit, Notepad…), сохраните его в виде файла с именем, скажем, test01.cpp (если вы новичок, лучше всего поместить этот файл в вашем домашнем каталоге (home directory), то есть, например, /home/jones в Unix).

Для компиляции файла исходного кода, введите следующую команду (на большинстве open-source UNIX-подобных О.С.) в консоли или в окне терминала:

g++ test01.cpp -o test01

Чтобы запустить бинарный исполняемый файл test01, который был произведен путем компиляцией (при условии , что не было никаких ошибок), введите следующее:

./test01

Каждый раз, когда вы изменяете test01.cpp файл исходного кода, вам нужно скомпилировать его снова , если вы хотите, чтобы изменения были отражены в test01 исполняемый файл (введите up-arrow key на клавиатуре , чтобы вызывать команды).

 

2.

Вы можете использовать  //  чтобы ввести примечание:

using namespace std;         // Использование стандартного имен.
#
include <iostream>          // используется iostream библиотека.

int main ()                  // главная процедура программы.
{
double a;                
// Декларация переменной а.

 

a = 456.47;
a = a + a * 21.5 / 100;   // Расчет.
cout
<< a << endl;        // Отображение содержимого a.

return 0;                 // Конец программы.
}

Вывод
554,611

 

(Возможность использования  //   чтобы печатать замечания добавлен C в C99 и ANSI C 2000)

3.

Ввод с клавиатуры и вывода на экран может быть выполнено через cout << and cin >>:

using namespace std;
#include
<iostream>

int main()
{
int
a;                    // целочисленная переменная
char
s [100];     // s указывает на строку максимум 99 символов
cout
<< “Это пример программы.” << endl;

cout << endl;

cout << “Введите свой возраст: “;
cin
>> a;

cout << “Введите ваше имя: “;
cin
>> s;

cout << endl;

cout << “Привет “ << s << “, тебе ” << a << ” лет.” << endl;
cout
<< endl << endl << “До свидания!” << endl;

return 0;
}

Вывод
Это пример программы. 

Введите свой возраст: 12 
Введите ваше имя: Эдмонд
        

Привет Эдмон, тебе 12 лет. 

До свидания!

 

4.

Переменные могут быть объявлены влюбом месте внутри кода:

using namespace std;
#include <iostream>

int main ()
{
double a;

cout << “Здравствуйте, это тест программы.” << endl;

cout << ” Введите параметра а: “;
cin >> a;

   a = (a + 1) / 2;

double c;

c = a * 5 + 1;

cout << ” с содержит: ” << c << endl;

int i, j;

i = 0;
j = i + 1;

cout << “j содержит: ” << j << endl;

return 0;
}

 

 

Вывод
Здравствуйте, это тест программы. 
Введите параметра а: 7
 
с содержит: 21
 
j содержит: 1

 

Может вам стоит использовать эту функцию , чтобы сделать ваш исходный код более удобным для чтения и не испортить его. 
Как и в C, переменные могут быть инкапсулированы между {} блоков. Тогда они являются локальными в области видимости в зоне инкапсулированного между {и}. Что бы ни случилось с такими переменными внутри инкапсулированного зоны, не будет иметь никакого эффекта вне зоны:

using namespace std;
#include <iostream>

int main ()
{
double a;

cout << “Введите число: “;
cin >> a;

{
int a = 1;
a = a * 10 + 4;
cout << “Местный номер: ” << a << endl;
}

cout << “Вы набрали: ” << a << endl;

return 0;
}

 

 

Вывод
Введите число: 9 
Местный номер: 14
 
Вы набрали: 9

 

5.

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

using namespace std;
#include <iostream>

int main ()
{
double a = 12 * 3.25;
double b = a + 1.112;

cout << “a содержит: ” << a << endl;
cout << “b содержит: ” << b << endl;

a = a * 2 + b;

double c = a + b * a;

cout << “c содержит: ” << c << endl;

return 0;
}

 

 

Вывод
а содержит: 39 
b содержит: 40,112 
с содержит: 4855,82

 

6.

C ++ позволяет объявлять переменную быть локальны в цикла:

используя патезрасе;
#include
<iostream>

using namespace std;
#include
<iostream>

int main ()
{
int
i;                       // Простая декларация i
i
= 487;

for (int i = 0; i < 4; i++)  // Локальная декларация i
{
cout
<< i << endl;        // Это выводит 0, 1, 2 and 3
}

cout << i << endl;           // Это выводит 487

return 0;
}

 

Вывод
0
1
2
3
487

 

 

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

using namespace std;
#include <iostream>

int main ()
{

for (int i = 0; i < 4; i++)
{
cout << i << endl;
}

cout << i << endl;           // Плохой практика!
i += 5;                      // Плохой практика!
cout << i << endl;           // Плохой практика!

return 0;
}

 

Gnu C++ compiler complain
t.cpp: In function ‘int main()’:
t.cpp:12: error: name lookup of ‘i’ changed for new ISO ‘for’ scoping
t.cpp:7: error:   using obsolete binding at ‘i’

 

7.

Глобальная переменная может быть доступна ,даже если другая переменная с тем же именем объявлена внутри функции:

using namespace std;
#include <iostream>

double a = 128;

int main ()
{
double a = 256;

cout << “Локальная a:  ” << a   << endl;
cout << “Global a: ” << ::a << endl;

return 0;
}

 

 

Вывод
Локальная a: 256
Global a: 128

 

8.

Можно сделать одну переменную быть другим:

using namespace std;
#include <iostream>

int main ()
{
double a = 3.1415927;

double &b = a;                            // b тепер a

b = 89;

cout << “a содержит: ” << a << endl;     // отображается 89.

return 0;
}

 

 

Вывод
а содержит: 89

 

 

(Если вы привыкли к указателям и абсолютно хотите знать ,что происходит, просто подумайте double &= a транслируется в double *= &a и все последующие б заменяются на * б .)

Значение ссылочного б не может быть изменен после его декларации. Например, вы не можете писать, несколько строк дальше, &= c, ожидая , что б теперь с. Это не будет работать. Все сказано в декларации линии b . Ссылка б и переменная a  женаты на этой линии, и ничто не будет разделить их. Ссылки могут быть использованы, чтобы разрешить функции модифицировать вызывающей переменную:

using namespace std;
#include <iostream>

void change (double &r, double s)
{
r = 100;
s = 200;
}

int main ()
{
double k, m;

k = 3;
m = 4;

change (k, m);

cout << k << “, ” << m << endl;        // отображается 100, 4.

return 0;
}

 

 

Вывод
100, 4

 

 

Если вы привыкли к указателям в C и интересно, как именно программа выше работает, вот как компилятор C ++ будет перевести его на C:

using namespace std;
#include <iostream>

void change (double *r, double s)
{
*r = 100;
s = 200;
}

int main ()
{
double k, m;

k = 3;
m = 4;

change (&k, m);

cout << k << “, ” << m << endl;        // отображается 100, 4.

return 0;
}

 

 

Вывод
100, 4

 

 

Ссылка может использоваться, чтобы позволить функции возвратить переменную:

using namespace std;
#include
<iostream>

double &biggest (double &r, double &s)
{
if
(r > s) return r;
else
       return s;
}

int main ()
{
double
k = 3;
double
m = 7;

cout << “k: ” << k << endl;       // отображается 3
cout
<< “m: ” << m << endl;       // отображается 7
cout
<< endl;

biggest (k, m) = 10;

cout << “k: ” << k << endl;       // отображается 3
cout
<< “m: ” << m << endl;       // отображается 10
cout
<< endl;

biggest (k, m) ++;

cout << “k: ” << k << endl;       // отображается 3
cout
<< “m: ” << m << endl;       // отображается 11
cout
<< endl;

return 0;
}

 

 

Вывод
k: 3
m: 7
k: 3
m: 10k: 3
m: 11

 

 

Опять же, при условии, что вы использовали арифметические операции над указателями, и если вам интересно, как программа выше работает, только представьте себе, что компилятор перевел его на следующей стандартной программы C:

 

 

using namespace std;
#include <iostream>

double *biggest (double *r, double *s)
{
if (*r > *s) return r;
else         return s;
}

int main ()
{
double k = 3;
double m = 7;

cout << “k: ” << k << endl;
cout << “m: ” << m << endl;
cout << endl;

(*(biggest (&k, &m))) = 10;

cout << “k: ” << k << endl;
cout << “m: ” << m << endl;
cout << endl;

(*(biggest (&k, &m))) ++;

cout << “k: ” << k << endl;
cout << “m: ” << m << endl;
cout << endl;

return 0;
}

 

 

Вывод
k: 3
m: 7
k: 3
m: 10k: 3
m: 11

 

Для людей, которым приходится иметь дело с указателями когда им не нравится, ссылки являются полезными для эффективного un-pointer переменных. Остерегайтесь, это можно считать плохой практикой и может принести вам неприятности.Смотрите, например http://web.archive.org/web/20131011080757/http://www.embedded.com/electronics-blogs/programming-pointers/4023307/References-vs-Pointers

using namespace std;
#
include <iostream>

double *silly_function ()    // Эта функция возвращает указатель на double
{
static double r = 342;
return &r;
}

int main ()
{
double *a;

a = silly_function();

double &b = *a;          // Теперь b является двойной по отношению к очки!

b += 1;                  // Отлично!
b = b * b;               // Нет необходимости писать *а везде!
b += 4;

cout << ” Содержание *a, b and r: ” << b << endl;

return 0;
}

 

 

Вывод
Содержание *a, b and r: 117653

 

9.

Namespace может быть объявлен.Переменные, объявленные в namespace можно использовать благодаря :: оператора:

using namespace std;
#include <iostream>
#include <cmath>

namespace first
{
int a;
int b;
}

namespace second
{
double a;
double b;
}

int main ()
{
first::a = 2;
first::b = 5;

second::a = 6.453;
second::b = 4.1e4;

cout << first::a + second::a << endl;
cout << first::b + second::b << endl;

return 0;
}

 

 

Вывод
8,453
41005

 

10.

Если функция содержит только простые строки кода, не используетдля цикла или тому подобное, она может быть объявлена как inline . Это означает, что его код будет доступен везде где функция используется. Это нечто вроде макро. Основным преимуществом является что программа будет работать быстрее. Небольшой недостаток заключается в том, что код будет больше, так как полный код функции вставляли везде, где он используется:

using namespace std;
#include <iostream>
#include <cmath>

inline double hypothenuse (double a, double b)
{
return sqrt (a * a + b * b);
}

int main ()
{
double k = 6, m = 9;

// Next two lines produce exactly the same code:

cout << hypothenuse (k, m) << endl;
cout << sqrt (k * k + m * m) << endl;

return 0;
}

 

 

Вывод
10,8167
10,8167

 

 

(Inline функции были добавлены в C в C99 и ANSI C 2000)

11.

Вы знаете классические структуры контроля C: forifdowhileswitch… C ++ добавляет еще одну структуру контроля под названием EXCEPTION:

 

using namespace std;
#
include <iostream>
#
include <cmath>

int main ()
{
int a, b;

cout << “Введите номер: “;
cin >> a;
cout << endl;

try
{
if (a > 100) throw 100;
if (a < 10)  throw 10;
throw a / 3;
}
catch (int result)
{
cout << “Результат: ” << result << endl;
b = result + 1;
}

cout << “b содержит: ” << b << endl;

cout << endl;

// другой пример использования исключений (exception):

char zero []     = “ ноль”;
char pair []     = “пара”;
char notprime [] = “не простой”;
char prime []    = “ простой”;

try
{
if (a == 0) throw zero;
if ((a / 2) * 2 == a) throw pair;
for (int i = 3; i <= sqrt (a); i++)
{
if ((a / i) * i == a) throw notprime;
}
throw prime;
}
catch (char *conclusion)
{
cout << “ Номер, который вы ввели “<< conclusion << endl;
}

cout << endl;

return 0;
}

Вывод
Введите номер: 5 

Результат: 10 
b содержит: 11 

Номер, который вы ввели простое

 

12.

Можно определить параметры поумолчанию для функций:

using namespace std;
#include <iostream>

double test (double a, double b = 7)
{
return a – b;
}

int main ()
{
cout << test (14, 5) << endl;    // отображается 14 – 5
cout << test (14) << endl;       // отображается 14 – 7

return 0;
}

 

 

Вывод
9
7

 

13.

Одним изважных преимуществ C ++ является функция OVERLOAD. Различные функции могут иметь такое же имя , при условии, что позволяет компилятору проводить различие между ними: количество параметров, типы параметров…

using namespace std;
#include <iostream>

double test (double a, double b)
{
return a + b;
}

int test (int a, int b)
{
return a – b;
}

int main ()
{
double   m = 7,  n = 4;
int      k = 5,  p = 3;

cout << test(m, n) << ” , ” << test(k, p) << endl;

return 0;
}

 

 

Вывод
11, 2

 


14.

OPERATOR OVERLOADING (ПЕРЕГРУЗКА ОПЕРАТОРОВ) может использоваться для переопределения базовых символических операторов для новых видов параметров:

using namespace std;
#include
<iostream>

struct vector
{
double
x;
double
y;
};

vector operator * (double a, vector b)
{
vector
r;

r.x = a * b.x;
r
.y = a * b.y;

return r;
}

int main ()
{
vector
k, m;              // Не нужно вводить “struct vector

k.x =  2;                 // иметь возможность написать
k
.y = -1;                 // k = vector (2, -1)
// смотрите раздел 19.

m = 3.1415927 * k;        // Волшебство!

cout << “(” << m.x << “, ” << m.y << “)” << endl;

return 0;
}

Вывод
(6,28319, -3,14159)

 

 

Кроме умножения, 43 другие основные операторы C ++ могут быть перегружены, в том числе + =++ , массив [] , и так далее… << оператор, как правило, используется для двоичного сдвига целых чисел, могут быть перегружены, чтобы дать вывод потоку вместо этого (например, cout <<). Можно перегрузить << оператора далее для вывода новых типов данных, как векторы:

using namespace std;
#include <iostream>

struct vector
{
double x;
double y;
};

ostream& operator << (ostream& o, vector a)
{
o << “(” << a.x << “, ” << a.y << “)”;
return o;
}

int main ()
{
vector a;

a.x = 35;
a.y = 23;

cout << a << endl;     // Отображается (35, 23)

return 0;
}

 

 

Вывод
(35, 23)

 

15.

Устали определения той же самой функции пять раз?Одно из определений для INT параметров типа, одно из определений для double параметров типа, одно из определений для float параметров типа … Не забыли один тип? Что делать , если используется новый тип данных? Нет проблем: C ++ компилятор может автоматически генерировать каждую версию функции, которая необходима! Просто скажите ему, как функция выглядит следующим путем объявляя template функции:

using namespace std;
#include <iostream>

template <class ttype>
ttype minimum (ttype a, ttype b)
{
ttype r;

r = a;
if (b < a) r = b;

return r;
}

int main ()
{
int i1, i2, i3;
i1 = 34;
i2 = 6;
i3 = minimum (i1, i2);
cout << “Самые маленькие: ” << i3 << endl;

double d1, d2, d3;
d1 = 7.9;
d2 = 32.1;
d3 = minimum (d1, d2);
cout << “Самые маленькие: ” << d3 << endl;

cout << “Самые маленькие: ” << minimum (d3, 3.5) << endl;

return 0;
}

 

 

Вывод
Самые маленькие: 6 
Самые маленькие: 7.9
 
Самые маленькие: 3,5

 

 

Функция minimum  используется три раза в вышеуказанной программе, но компилятор C ++ генерирует только две версии этого: int minimum (int a, int b) и double minimum (double a, double b) . Это работает для всей части программы.

Что произойдет, если вы пытались что – то вроде расчета minimum (i1, d1)? Компилятор сообщил бы, что, это ошибка. Это потому,  что шаблон (template) утверждает, что оба параметра одного типа.

 

Вы можете использовать произвольное число различных шаблонных типов данных в определении шаблона. И не все типы параметров должны быть шаблоны, некоторые из них могут быть стандартных типов или определяемый пользователем (char,intdouble…). Ниже приведен пример , в котором minimum функция принимает параметры любого типа (разные или одинаковые) и выводит значение , которое имеет тип первого параметра:

using namespace std;
#include <iostream>

template <class type1, class type2>
type1 minimum (type1 a, type2 b)
{
type1 r, b_converted;
r = a;
b_converted = (type1) b;
if (b_converted < a) r = b_converted;
return r;
}

int main ()
{
int i;
double d;

i = 45;
d = 7.41;

cout << “Самые маленькие: ” << minimum (i, d) << endl;
cout << “Самые маленькие: ” << minimum (d, i) << endl;
cout << “Самые маленькие: ” << minimum (‘A’, i) << endl;

return 0;
}

 

 

Вывод
Самые маленькие: 7 
Самые маленькие: 7,41
 
Самые маленькие: –

 

(The ASCII код символа ‘-‘ 45 когда код “А” 65.)

16.

Ключевые слова new и delete могут быть использованы для выделения и освобождения памяти. Они более чистые, чем функции malloc и free от стандарта C.

new [] и delete [] используются для массивов (arrays).


using namespace std;
#include <iostream>
#include <cstring>

int main ()
{
double *d;                         // d – переменная, цель которой
//
состоит в том, чтобы содержать
//
адрес зоны, где double расположено

d = new double;                    // New выделяет зону памяти
//
достаточно большой, чтобы содержать                                                                   // Double и возвращает его адрес.
// Этот адрес хранится в d
.
*d
= 45.3;                         // Количество 45.3 хранится
// внутри зоны памяти,
// адрес которого указан на d
.
cout
<< “Введите число: “;
cin
>> *d;

*d = *d + 5;

cout << “Результат: ” << *d << endl;

delete d;                          // delete освобождает зоны памяти,
// адрес которого указан по
// указателю d
. Теперь мы не
// можем использовать эту зону.

d = new double[15];                // выделяет зону для массива
// 15 double. Примечание, каждый
// 15 double будут созданы.
// Это бессмысленно здесь , но
// это важно при использовании
// типа данных, для которого нужен
                                      // его конструктор использовался                                      // для каждый instance.

   d[0] = 4456;
d[1] = d[0] + 567;

cout << “Содержание d [1]: ” << d[1] << endl;

delete [] d;                       // delete [], освободит зону памяти.
// Отметьте, каждый 15 double
// будут разрушены. Это бессмысленно

                                      // здесь, но это важно при
// использовании типа данных,
// для которого нужен его деструктор
// использовался для каждого instance
// (~ method). Используя delete
// без [], освободит зону памяти,
// не разрушая каждый 15 instance.
// Это может вызвать утечку памяти.

int
n = 30;

d = new double[n];                 // New может быть использован для выделения
// массива произвольного размера.

for (int i = 0; i < n; i++)
{
d[i] = i;
}

delete [] d;

char *s;

s = new char[100];

strcpy (s, “Здравствуйте!”);

cout << s << endl;

delete [] s;

return 0;
}

Вывод
Введите число: 6 
Результат: 11
 
Содержание
d [1]: 5023 
Здравствуйте!

 

 

17.

В стандартном С,structсодержит только данные. В C ++ определение struct может также включать в себя функции. Эти функции принадлежат struct и предназначены для работы на данных struct. Эти функции называются METHODS. В приведенном ниже примере определяет метод surface() на struct vector:

using namespace std;
#include <iostream>

struct vector
{
double x;
double y;

double surface ()
{
double s;
s = x * y;
if (s < 0) s = -s;
return s;
}
};

int main ()
{
vector a;

a.x = 3;
a.y = 4;

cout << “Поверхность a: ” << a.surface() << endl;

return 0;
}

 

 

Вывод
Поверхность a: 12

 



В приведенном выше примере, является INSTANCE на struct “vector”. (Обратите внимание,что ключевое слово ” struct ” не было необходимо при объявлении вектора а .)

 

Как функция, метод может быть overload любого оператора C ++, иметь любое количество параметров (все же один параметр всегда неявен: instance – экземпляр которого он действует), возвращать любой тип параметра, или не возвращать параметр вообще. Что такое class (класс) ? Это struct (структура), которая сохраняет свои данные скрытыми. Только методы class могут получить доступ к данным. Вы не можете получить доступ к данным непосредственно, если это не авторизовано public: directive. Ниже приведен пример class определения. Он ведет себя точно так же, как struct выше примере, поскольку данные class data x и y авторизовано как public:

using namespace std;
#include
<iostream>

class vector
{
public
:

double x;
double
y;

double surface ()
{
double
s;
s
= x * y;
if
(s < 0) s = -s;
return
s;
}
};

int main ()
{
vector
a;

a.x = 3;
a
.y = 4;

cout << “Поверхность a: ” << a.surface() << endl;

return 0;
}

Вывод
Поверхность a: 12

 

 

В приведенном выше примере,  main() функция изменяет data instance a  посредственно, используя a.x = 3 и a.y = 4. Это стало возможным благодаря public: directive в определении класса. Это считается плохой практикой. Смотрите главу 30.

 

Способ разрешено изменять переменные instance на которого он действует:


using namespace std;
#include <iostream>

class vector
{
public:

double x;
double y;

vector its_opposite()
{
vector r;

r.x = -x;
r.y = -y;

return r;
}

void be_opposited()
{
x = -x;
y = -y;
}

void be_calculated (double a, double b, double c, double d)
{
x = a – c;
y = b – d;
}

vector operator * (double a)
{
vector r;

r.x = x * a;
r.y = y * a;

return r;
}
};

int main ()
{
vector a, b;

a.x = 3;
a.y = 5;

b = a.its_opposite();

cout << “Vector a: ” << a.x << “, ” << a.y << endl;
cout << “Vector b: ” << b.x << “, ” << b.y << endl;

b.be_opposited();
cout << “Vector b: ” << b.x << “, ” << b.y << endl;

a.be_calculated (7, 8, 3, 2);
cout << “Vector a: ” << a.x << “, ” << a.y << endl;

a = b * 2;
cout << “Vector a: ” << a.x << “, ” << a.y << endl;

a = b.its_opposite() * 2;
cout << “Vector a: ” << a.x << “, ” << a.y << endl;

cout << “x противоположный на a: ” << a.its_opposite().x << endl;

return 0;
}

 

 

Вывод
Вектор: с 3, 5 
Вектор Ъ: -3, -5
 
Вектор
B: 3, 5 
Вектор: с
 4, 6 
Вектор а: 6, 10
 
Вектор: с
 -6, -10 
x
противоположный на a: 6

 

18.

Очень специальные и основные методы CONSTRUCTOR и DESTRUCTOR.Они автоматически вызывается всякий раз , когда экземпляр класса создается или разрушается (декларация переменной, конец программы  newdelete …).Конструктор инициализирует переменные instance, сделает некоторые вычисления, выделяет памяти для instance, произведет некоторый текст… независимо от того, что необходимо.Ниже приведен пример определения класса с двумя перегруженными конструкторами (overloaded constructors):

 

using namespace std;
#include
<iostream>

class vector
{
public
:

double x;
double
y;

vector ()                     // то же самое имя как класс
{
x
= 0;
y
= 0;
}

vector (double a, double b)
{
x
= a;
y
= b;
}

};

int main ()
{
vector
k;                     // vector () называется

cout << “vector k: ” << k.x << “, ” << k.y << endl << endl;

vector m (45, 2);             // vector (double, double) называется

cout << “vector m: ” << m.x << “, ” << m.y << endl << endl;

k = vector (23, 2);           // vector создано,                                //копировано на k, а затем удален
cout
<< “vector k: ” << k.x << “, ” << k.y << endl << endl;

return 0;
}

 

Вывод
vector k: 0, 0

vector m: 45, 2

vector k: 23, 2

 

 

Это – хорошая практика, чтобы попытаться не перегрузить конструкторов. Лучше объявлять только одного конструктора и давать ему параметры по умолчанию везде, где возможно:

 

 

using namespace std;
#include <iostream>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}
};

int main ()
{
vector k;
cout << “vector k: ” << k.x << “, ” << k.y << endl << endl;

vector m (45, 2);
cout << “vector m: ” << m.x << “, ” << m.y << endl << endl;

vector p (3);
cout << “vector p: ” << p.x << “, ” << p.y << endl << endl;

return 0;
}

 

Вывод
vector k: 0, 0

vector m: 45, 2

vector p: 3, 0

 

 

Деструктор часто нет необходимости. Вы можете использовать его, чтобы сделать некоторые расчеты, когда экземпляр (instance) уничтожается или выводит какой-то текст для debugging… Но если переменные instance указывают в некоторой выделенной памяти тогда роль деструктора имеет важное значение: он должен освободить эту память! Ниже приведен пример такого приложения:

 

using namespace std;
#include <iostream>
#include <cstring>

class person
{
public:

char *name;
int age;

person (char *n = “no name”, int a = 0)
{
name = new char [100];                 // лучше, чем malloc!
strcpy (name, n);
age = a;
cout << “Instance initialized, 100 bytes allocated” << endl;
}

~person ()                               // деструктор
{
delete name;                          // вместо free!

// delete [] name было бы
// более академическим, но
// это не важно здесь, так
// как не содержит C
++ sub-objects,
// которые должны быть удалены.

cout << “Instance going to be deleted, 100 bytes freed” << endl;
}
};

int main ()
{
cout << “Здравствуйте! ” << endl << endl;

person a;
cout << a.name << “, age ” << a.age << endl << endl;

person b (“John”);
cout << b.name << “, age ” << b.age << endl << endl;

b.age = 21;
cout << b.name << “, age ” << b.age << endl << endl;

person c (“Miki”, 45);
cout << c.name << “, age ” << c.age << endl << endl;

cout << “Bye!” << endl << endl;

return 0;
}

 

Вывод
Hello!

Instance initialized, 100 bytes allocated
no name, age 0

Instance initialized, 100 bytes allocated
John, age 0

John, age 21

Instance initialized, 100 bytes allocated
Miki, age 45

Bye!

Instance going to be deleted, 100 bytes freed
Instance going to be deleted, 100 bytes freed
Instance going to be deleted, 100 bytes freed

 

 

Вот краткий пример определения класса массива. Метод, который является overload [] оператора и выводит ссылку (&) используется для того, чтобы генерировать ошибку, если предпринимается попытка получить доступ к данным за пределами массива:

 

 

using namespace std;
#include <iostream>
#include <cstdlib>

class array
{
public:
int size;
double *data;

array (int s)
{
size = s;
data = new double [s];
}

~array ()
{
delete [] data;
}

double &operator [] (int i)
{
if (i < 0 || i >= size)
{
cerr << endl << “за пределами” << endl;
exit (EXIT_FAILURE);
}
else return data [i];
}
};

int main ()
{
array t (5);

t[0] = 45;                       // OK
t[4] = t[0] + 6;                 // OK
cout << t[4] << endl;            // OK

t[10] = 7;                       // ошибка!

return 0;
}

 

Вывод
51

за пределами

 

19.

Если вы разыгрываете объект как вектор, все будет происходить правильно.Например, если вектор k содержит (4, 7) , после заброса = k вектором m  тоже будет содержать (4,7). Значения k.x и k.y просто были скопированы на m.x и m.y. Теперь предположим, что вы играете с объектами , как человек класса выше. Эти объекты содержат указатель на character string. Если вы накладываете на person объекта, написав = r то , что некоторые необходимые функции должны осуществляться, чтобы сделать р быть правильным копиям r . В противном случае p.name будет указывать на ту же физическую строку символов как r.name. Более того, бывший символьная строка , на которую указывает p.name теряется и становится зомби памяти. Результат будет иметь катастрофические последствия : беспорядок указателей и потерянных данных. Методы, которые будут делать эту работу являются COPY CONSTRUCTOR и перегрузка оператора =:

using namespace std;
#include <iostream>
#include <cstring>

class person
{
public:

char *name;
int age;

person (char *n = “no name”, int a = 0)
{
name = new char[100];
strcpy (name, n);
age = a;
}

person (const person &s)      // COPY CONSTRUCTOR
{
name = new char[100];
strcpy (name, s.name);
age = s.age;
}

person& operator= (const person &s)  // overload =
{
strcpy (name, s.name);
age = s.age;
return *this;
}

~person ()
{
delete [] name;
}
};

void modify_person (person& h)
{
h.age += 7;
}

person compute_person (person h)
{
h.age += 7;
return h;
}

int main ()
{
person p;
cout << p.name << “, age ” << p.age << endl << endl;
// вывод: no name, age 0

person k (“John”, 56);
cout << k.name << “, age ” << k.age << endl << endl;
// вывод: John, age 56

p = k;
cout << p.name << “, age ” << p.age << endl << endl;
// вывод: John, age 56

p = person (“Bob”, 10);
cout << p.name << “, age ” << p.age << endl << endl;
// вывод: Bob, age 10

// Ни copy constructor, ни overload «=»
// необходимы для этой операции,
// которая изменяет p так как, ссылка к
// p передана к функции modify_person:
modify_person (p);
cout << p.name << “, age ” << p.age << endl << endl;
// вывод: Bob, age 17

// copy constructor вызывается, чтобы передать полную
// копию p к функции compute_person. Использование
// функции, которое копирует, чтобы сделать ее
// вычисления тогда копией той измененной копии,
// сделано возвратить результат. Наконец,
overload =
// вызывается, чтобы приклеить ту вторую копию внутри k
:
k
= compute_person (p);
cout
<< p.name << “, age ” << p.age << endl << endl;
   // вывод: Bob, age 17
cout
<< k.name << “, age ” << k.age << endl << endl;
   // вывод: Bob, age 24

return 0;
}

 

Вывод
no name, age 0

John, age 56

John, age 56

Bob, age 10

Bob, age 17

Bob, age 17

Bob, age 24

 

 

Конструктор копирования позволяет вашей программе делать копии экземпляров при выполнении вычислений. Это ключевой метод. В процессе вычислений экземпляры создаются для хранения промежуточных результатов. Они изменены, брошены и разрушены без вас. Именно поэтому эти методы могут быть полезны даже для простых объектов (см главу 14).

Во всех приведенных выше примерах методы определены внутри определения класса. Это автоматически делает их inline methods.

20.

Если метод не может быть встроенным (inline), или вы не хотите, чтобы быть встроенным, или если вы хотите определение класса, чтобы содержать минимальное количество информации (или вы просто хотите обычный отдельный .h header файл и .cpp исходный код файл), то вам нужно только положить прототип метода внутри класса и определит метод ниже класса (или в отдельном исходном файле .cpp):

using namespace std;
#include <iostream>

class vector
{
public:

double x;
double y;

double surface();         // ; и no {} показывают что они прототипы
};

double vector::surface()
{
double s = 0;

for (double i = 0; i < x; i++)
{
s = s + y;
}

return s;
}

int main ()
{
vector k;

k.x = 4;
k.y = 5;

cout << “Поверхность: ” << k.surface() << endl;

return 0;
}

 

Вывод
Поверхность: 20

 

 

Для новичков:

Если вы собираетесь разрабатывать серьезную программу C или C ++, вам нужно отделить исходный код в .h header файлов и .cpp исходных файлов. Это короткий пример того, как это делается. Программа выше разделена на три файла:

header файл, vector.h :

class vector
{
public:

double x;
double y;

double surface();
};

Исходный файл vector.cpp :

using namespace std;
#include “vector.h”

double vector::surface()
{
double s = 0;

for (double i = 0; i < x; i++)
{
s = s + y;
}

return s;
}

И еще один исходный файл main.cpp :

using namespace std;
#include <iostream>
#include “vector.h”

int main ()
{
vector k;

k.x = 4;
k.y = 5;

cout << “Surface: ” << k.surface() << endl;

return 0;
}

Предполагая , что vector.cpp является совершенным, в надо скомпилировать еще раз и навсегда в  .o “object file”. Приведенная ниже команда производит этот код файл объекта, называется vector.o:

g++ -c vector.cpp

Каждый раз, когда Вы изменяете main.cpp исходный файл, Вы компилируете его в исполняемый файл, например test20. Вы говорите компилятору, что он должен соединить vector.o объектный файл в  последную test20:

 

g++ main.cpp vector.o -o test20

 

Запустите исполняемый файл следующим образом:

 

./test20

 

Это имеет несколько преимуществ:

 

  • Исходный код vector.cpp должен быть компилирован только один раз. Это экономит много времени на больших проектах. (Соединение vector.o файл в test20 исполняемый файл очень быстро.
  • Вы можете дать кому – то .h файл и .o файл (ы). Таким образом, они могут использовать свое программное обеспечение , но не смогут изменить его , потому что они не имеют .CPP – файл (ы) (не слишком полагаться на это, пока вы не овладеете эти вопросы).

Обратите внимание , что вы также можете собрать (compile) main.cpp  в объектный файл, а затем соединить его с vector.o :

g++ -c main.cpp

g++ main.o vector.o test20

Это блуждает далеко от ” differences between C and C++ ” тема, но если вы хотите выглядеть как настоящий программист, вы должны конденсироваться выше команды в Makefile и собрать используя make команду. Содержание файла ниже – упрощенная версия такого Makefile.Скопируйте его в файл с именем Makefile . Пожалуйста , обратите внимание, и это очень важно, что пространство перед g++ команд является обязательным и что это символ Tab. Не вводите пробел здесь. Вместо этого используйте ключ табулирования (слева от клавиатуры, выше caps lock).

test20: main.o vector.o
g
++ main.o vector.o -o test20

main.o: main.cpp vector.h
g
++ -c main.cpp

vector.o: vector.cpp vector.h
g
++ -c vector.cpp

Для того чтобы использовать Makefile для компиляции, введите следующую команду :

make test20

Команда ” make ” разберет через файл Makefile и выяснит то, что это должно сделать. Для начала это сказано, что test20 зависит от main.o и vector.o. Таким образом, это автоматически начнет, ” make main.o “, и ” make vector.o “.  Тогда это проверит, существует ли test20 уже и проверяет отметки даты test20, main.o и vector.o. Если test20 уже существует и main.o, и у vector.o есть отметка даты ранее, тогда test20, make команда решает, что текущая версия test20 последная, таким образом, этому нечего делается. Это просто сообщит, что ничего не сделало. Иначе, если test20 не существует, или main.o или vector.o более новый, чем test20, команда, которая создает актуальную версию test20, выполняется: g++ main.o vector.o -o test20.

Это следующая версия Makefile ближе к стандартному Makefile:

all: test20

test20: main.o vector.o
g
++ main.o vector.o -o test20

main.o: main.cpp vector.h
g
++ -c main.cpp

vector.o: vector.cpp vector.h
g
++ -c vector.cpp

clean:
rm
-f *.o test20 *~ #*

Вы запускаете компиляцию, просто набрав make команду. Первая строка в файле Makefile подразумевает , что если вы просто введите make вы хотели ” make test20 “:

make

Эта команда стирает все файлы , созданные во время компиляции и все файлы резервного копирования осуществляется:

make clean

21.

Когда метод применяется к instance, метод может использовать переменные этого instance, изменять их … Но иногда необходимо знать адрес instance. Нет проблем, ключевое слово this предназначено для этой цели:

 

 

using namespace std;
#include <iostream>
#include <cmath>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double module()
{
return sqrt (x * x + y * y);
}

void set_length (double a = 1)
{
double length;

length = this->module();

x = x / length * a;
y = y / length * a;
}
};

int main ()
{
vector c (3, 5);

cout << “Модуль вектора с: ” << c.module() << endl;

c.set_length(2);            // Трансформирует c в векторе размера 2.

cout << “Модуль вектора с: ” << c.module() << endl;

c.set_length();             // Превращает b в унитарном векторе.

cout << “Модуль вектора с: ” << c.module() << endl;

return 0;
}

 

Вывод
Модуль вектора с: 5,83095 
модуль вектора с: 2
 
модуль вектора с: 1

 

22.

Конечно, можно объявить массив объектов:

using namespace std;
#include <iostream>
#include <cmath>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double module ()
{
return sqrt (x * x + y * y);
}
};

int main ()
{
vector s [1000];

vector t[3] = {vector(4, 5), vector(5, 5), vector(2, 4)};

s[23] = t[2];

cout << t[0].module() << endl;

return 0;
}

Вывод
6,40312

 

23.

Вот пример полного определения класса:

using namespace std;
#include <iostream>
#include <cmath>

class vector
{
public:

double x;
double y;

vector (double = 0, double = 0);

vector operator + (vector);
vector operator – (vector);
vector operator – ();
vector operator * (double a);
double module();
void set_length (double = 1);
};

vector::vector (double a, double b)
{
x = a;
y = b;
}

vector vector::operator + (vector a)
{
return vector (x + a.x, y + a.y);
}

vector vector::operator – (vector a)
{
return vector (x – a.x, y – a.y);
}

vector vector::operator – ()
{
return vector (-x, -y);
}

vector vector::operator * (double a)
{
return vector (x * a, y * a);
}

double vector::module()
{
return sqrt (x * x + y * y);
}

void vector::set_length (double a)
{
double length = this->module();

x = x / length * a;
y = y / length * a;
}

ostream& operator << (ostream& o, vector a)
{
o << “(” << a.x << “, ” << a.y << “)”;
return o;
}

int main ()
{
vector a;
vector b;
vector c (3, 5);

a = c * 3;
a = b + c;
c = b – c + a + (b – a) * 7;
c = -c;

cout << ” Модуль вектора c: ” << c.module() << endl;

cout << “The content of vector a:  ” <<  a << endl;
cout << ” Содержание вектора a: ” << -a << endl;

c.set_length(2);            // Трансформирует c в векторе размера 2.

a = vector (56, -3);
b = vector (7, c.y);

b.set_length();             // Превращает b в унитарном векторе.
cout << “
содержит b: ” << b << endl;

double k;
k = vector(1, 1).module();  // k содержит 1.4142.
cout << “k содержит: ” << k << endl;

return 0;
} 

Вывод
Модуль вектора с: 40,8167 
Содержание вектора а: (3, 5)
 
содержит а: (-3, -5)
 
содержит
b: (0.971275, 0,23796) 
k содержит: 1,41421

 

 

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

vector operator + (vector a, vector b)
{
return vector (a.x + b.x, a.y + b.y);
}

 

В примере полного определения класса, выше, умножение вектора double определен. Предположим, мы хотим умножение double вектором. Тогда мы должны написать (isolated function) изолированную функцию вне класса:

vector operator * (double a, vector b)
{
return vector (a * b.x, a * b.y);
}

 

Конечно, ключевые слова, new и delete для instance классов тоже. Более того, new автоматически вызывает конструктор для инициализации объектов, а также delete автоматически вызывает деструктор перед освобождением памяти instance переменные:

 

 

using namespace std;
#include <iostream>
#include <cmath>

class vector
{
public:

double x;
double y;

vector (double = 0, double = 0);

vector operator + (vector);
vector operator – (vector);
vector operator – ();
vector operator * (double);
double module();
void set_length (double = 1);
};

vector::vector (double a, double b)
{
x = a;
y = b;
}

vector vector::operator + (vector a)
{
return vector (x + a.x, y + a.y);
}

vector vector::operator – (vector a)
{
return vector (x – a.x, y – a.y);
}

vector vector::operator – ()
{
return vector (-x, -y);

}

vector vector::operator * (double a)
{
return vector (a * x, a * y);
}

double vector::module()
{
return sqrt (x * x + y * y);
}

void vector::set_length (double a)
{
vector &the_vector = *this;

double length = the_vector.module();

x = x / length * a;
y = y / length * a;
}

ostream& operator << (ostream& o, vector a)
{
o << “(” << a.x << “, ” << a.y << “)”;
return o;
}

int main ()
{
vector c (3, 5);

vector *r;                  // r представляет указатель на вектор.

r = new vector;             // new выделяет необходимую память
cout
<< *r << endl;         // чтобы провести векторы на переменной
// а, вызывается конструктор, который
// будет инициализировать его до 0, 0.
// Тогда, наконец, new
возвращает
// адрес вектора.

r->x = 94;
r
->y = 345;
cout
<< *r << endl;

*r = vector (94, 343);
cout
<< *r << endl;

*r = *r – c;
r
->set_length(3);
cout
<< *r << endl;

*r = (-c * 3  +  -*r * 4) * 5;
cout
<< *r << endl;

delete r;                   // Вызывает вектор деструктор
// затем освобождает память.

r = &c;                     // r указывает на вектор c
cout
<< *r << endl;

r = new vector (78, 345);   // Создает новый вектор.
cout << *r << endl;         // Конструктор инициализируется х и у
                               // векторы на 78 и 345
cout << “x компонент r: ” << r->x << endl;
cout << “x компонент r: ” << (*r).x << endl;

delete r;

r = new vector[4];          // создает массив из 4 векторов

r[3] = vector (4, 5);
cout << r[3].module() << endl;

delete [] r;                // удаляет массив

int n = 5;
r = new vector[n];

r[1] = vector (432, 3);
cout << r[1] << endl;

delete [] r;

return 0;
}

Вывод
(0, 0)
(94, 345)
(94, 343)
(0.77992, 2.89685)
(-60.5984, -132.937)
(3, 5)
(78, 345)
x компонент r: 78
x компонент r: 78
6.40312
(432, 3)

 

24.

Одна или более переменных в классе могут быть объявлены статичными (static). В этом случае, только один instance тех переменных существуют, разделенные всеми instance класса. Это должно быть инициализировано вне декларации класса:

using namespace std;
#include <iostream>

class vector
{
public:

double x;
double y;
static int count;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
count++;
}

~vector()
{
count–;
}
};

int vector::count = 0;

int main ()
{
cout << “Number of vectors:” << endl;

vector a;
cout << vector::count << endl;

vector b;
cout << vector::count  << endl;

vector *r, *u;

r = new vector;
cout << vector::count << endl;

u = new vector;
cout << a.count << endl;

delete r;
cout << vector::count << endl;

delete u;
cout << b.count << endl;

return 0;
}

 

Вывод
1
2
3
4
3
2

 

25.

Переменная класс также может быть const. Это так же, как статические, заисключением того, что дано значение внутри объявления класса , и это значение не может быть изменен:


using namespace std;
#include <iostream>

class vector
{
public:

double x;
double y;
const static double pi = 3.1415927;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double cylinder_volume ()
{
return x * x / 4 * pi * y;
}
};

int main()
{
cout << ” Значение pi: ” << vector::pi << endl << endl;

vector k (3, 4);

cout << “Результат: ” << k.cylinder_volume() << endl;

return 0;
}

 

Вывод
Значение pi: 3.14159

Результат: 28,2743

 

26.

Класс может быть получен (DERIVED) из другого класса.Новый класс наследуют (INHERIT) переменные и методы базового класса. Дополнительные переменные и / или способы могут быть добавлены:

using namespace std;
#include
<iostream>
#include
<cmath>

class vector
{
public
:

double x;
double
y;

vector (double a = 0, double b = 0)
{
x
= a;
y
= b;
}

double module()
{
return
sqrt (x*x + y*y);
}

double surface()
{
return
x * y;
}
};

class trivector: public vector    // тривектором получен из вектора
{
public
:
double
z;                      // добовлен на x and y из вектора

trivector (double m=0, double n=0, double p=0): vector (m, n)
{
z
= p;                      // Вектор конструктор будет
}                             
// вызываться до тривектором
// конструктора, с параметрами
// m
и n.

trivector (vector a)           // Что делать, если вектор
{                             
// приведен к тривектором
x
= a.x;
y
= a.y;
z
= 0;
}

double module ()               // определение module() для тривектором
{
return
sqrt (x*x + y*y + z*z);
}

double volume ()
{
return
this->surface() * z;         // или x * y * z
}
};

int main ()
{
vector
a (4, 5);
trivector
b (1, 2, 3);

cout << “a (4, 5)    b (1, 2, 3)    *r = b” << endl << endl;

cout << “Поверхность a: ” << a.surface() << endl;
cout
<< “Объем b: ” << b.volume() << endl;
cout
<< “Поверхность основания b: ” << b.surface() << endl;

cout << “Модуль a: ” << a.module() << endl;
cout
<< “Модуль b: ” << b.module() << endl;
cout
<< “Модуль основания b: ” << b.vector::module() << endl;

trivector k;
k
= a;               // благодаря тривектором (вектор) определение
// копия x
and y,       k.z = 0
vector
j;
j
= b;               // копия x and y.       b.z
vector *r;
r = &b;

cout << “Поверхность r: ” << r->surface() << endl;
cout << “Модуль r: ” << r->module() << endl;

return 0;
}

 

Вывод
a (4, 5)    b (1, 2, 3)    *r = b

Поверхность a: 20 
Объем
b: 6 
Поверхность основания
b: 2 
Модуль
a: с 6.40312 
Модуль
b: 3,74166 
Модуль основания b: 2,23607
 
Поверхность
r: 2 
Модуль
r: 2,23607

 

27.

(Если по крайней мере один из методов базового класса является виртуальным то ” header” из 4-х байт добавляется к каждому экземпляру (instance) классов. Это позволяет программе определить на что вектор на самом деле указывает.) (4 байта, вероятно , зависит от конкретной реализации. на 64 битной машине может быть это 8 байт …)

В приведенной выше программе,r->module() вычисляет модуль вектора, используя х и у , так как r был объявлен как вектор указатель. Тот факт, что r на самом деле указывает на тривектором, и это не принимается во внимание. Если вы хотите программу, чтобы проверил тип объекта и выбрал подходящий метод, то вы должны объявить, что метод как virtual (виртуальный) внутри базового класса.

using namespace std;
#include
<iostream>
#include
<cmath>

class vector
{
public
:

double x;
double
y;

vector (double a = 0, double b = 0)
{
x
= a;
y
= b;
}

virtual double module()
{
return
sqrt (x*x + y*y);
}
};

class trivector: public vector
{
public
:
double
z;

trivector (double m = 0, double n = 0, double p = 0)
{
x
= m;                  // Просто для игры, здесь
y
= n;                  // я не называю вектор конструктор,
z
= p;                  // и я заставляю конструктор
}                         
// тривектору делать всю работу.
// Тот же результат.

double module ()
{
return sqrt (x*x + y*y + z*z);
}
};

void test (vector &k)
{
cout << “Результат теста: ” << k.module() << endl;
}

int main ()
{
vector a (4, 5);
trivector b (1, 2, 3);

cout << “a (4, 5)    b (1, 2, 3)” << endl << endl;

vector *r;

r = &a;
cout << ” Модуль вектора а: ” << r->module() << endl;

r = &b;
cout << ” Модуль тривектора b: ” << r->module() << endl;

test (a);

test (b);

vector &s = b;

cout << “Модуль тривектора b: ” << s.module() << endl;

return 0;
}

 

Вывод
a (4, 5)    b (1, 2, 3)

Модуль вектора а: 6,40312 
Модуль тривектора
b: 3,74166 
Результат теста: 6,40312
 
Результат теста: 3,74166
 
Модуль тривектора
b: 3,74166

 

28.

Может быть ,вам интересно , если класс может быть получен из более чем одного базового класса. Ответ : да:

using namespace std;
#include <iostream>
#include <cmath>

class vector
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double surface()
{
return fabs (x * y);
}
};

class number
{
public:

double z;

number (double a)
{
z = a;
}

int is_negative ()
{
if (z < 0) return 1;
else       return 0;
}
};

class trivector: public vector, public number
{
public:

trivector(double a=0, double b=0, double c=0): vector(a,b), number(c)
{
}           // Конструктор тривектора вызывает конструктор
// вектор, а затем номер конструктора,
// и в этом примере ничего не делает больше.

double volume()
{
return fabs (x * y * z);
}
};

int main ()
{
trivector a(2, 3, -4);

cout << a.volume() << endl;
cout << a.surface() << endl;
cout << a.is_negative() << endl;

return 0;
}

 

Вывод
24
6
1

 

29.

Class derivation (производный класс) позволяет строить более сложные классы , построенные из базовых классов.Существует еще одно приложение Class derivation: позволяя программисту написать общие функции.Предположим , вы определяете базовый класс без каких – либо переменных. Это не имеет смысла использовать экземпляры (instance) этого класса в вашей программе. Но потом вы пишете функцию, целью которой является для сортировки экземпляров этого класса. Эта функция будет иметь возможность сортировать любой тип объекта при условии, что принадлежит к классу, полученного из этого базового класса! Единственным условием является то, что внутри каждого производного определения класса, все методы , что потребности функции сортировки корректно определены:

using namespace std;
#include
<iostream>
#include
<cmath>class octopus
{
public:

virtual double module() = 0;  // = 0 означает функция не определена.
// Это значит что экземпляры этого класса
// не могут быть объявлены.

};

double biggest_module (octopus &a, octopus &b, octopus &c)
{
double r = a.module();
if (b.module() > r) r = b.module();
if (c.module() > r) r = c.module();
return r;
}

class vector: public octopus
{
public:

double x;
double y;

vector (double a = 0, double b = 0)
{
x = a;
y = b;
}

double module()
{
return sqrt (x * x + y * y);
}
};

class number: public octopus
{
public:

double n;

number (double a = 0)
{
n = a;
}

double module()
{
if (n >= 0) return n;
else        return -n;
}
};

int main ()
{
vector k (1,2), m (6,7), n (100, 0);
number p (5),   q (-3),  r (-150);

cout << biggest_module (k, m, n) << endl;
cout << biggest_module (p, q, r) << endl;

cout << biggest_module (p, q, n) << endl;

return 0;
}

 

Вывод
100
150
100

 

 

Возможно, вы думаете : “Хорошо, что это хорошая идея вывести классы из класса octopus, потому что , так я могу применить его к instance методов и функции моего класса, которые были разработаны в общем виде для octopus класса. Но что, если есть другой базовый класс, с названием cuttlefish, который имеет очень интересные методы и функции тоже? Должен ли я сделать свой выбор между octopus  и cuttlefish , когда я хочу получить класс? ” Нет, конечно нет. Производный класс может быть получен из обоих octopus  и cuttlefish. Это полиморфизм. Производный класс просто должен определить методы , необходимые для octopus  вместе с методами , необходимыми для cuttlefish:

 

 

class octopus
{
virtual double module() = 0;
};

class cuttlefish
{
virtual int test() = 0;
};

class vector: public octopus, public cuttlefish
{
double x;
double y;

double module ()
{
return sqrt (x * x + y * y);
}

int test ()
{
if (x > y) return 1;
else       return 0;
}
}

 

30.

public:directive означает переменные или ниже методы могут получить доступ и использовать везде в программе.

 

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

 

Если вы хотите, переменные или методы должны быть доступны только для методов класса, то вы должны поместить ключевое слово private: перед ними.

 

Тот факт, что переменные или методы объявлены private  или protected означает , что ничто внешнее по отношению к классу не может получить доступ или использовать их. Это ИНКАПСУЛЯЦИЮ. (Если вы хотите, чтобы дать определенную функцию право на доступ к этим переменным и методам, то вы должны включить прототип этой функции внутри определения класса, которому предшествует friend ключевого слова.)

 

Хорошая практика должна заключить в капсулу все переменные класса. Это может показаться странным, если вы привыкли в С. Действительно структура только имеет смысл, если Вы можете получить доступ к его данным … В C ++ Вы должны создать методы, чтобы получить доступ к данным в классе. Пример ниже использует основной пример главы 17, который объявляет, что данные о классе защищены (protected):

using namespace std;
#include
<iostream>

class vector
{
protected
:

double x;
double
y;

public:

void set_x (int n)
{
x
= n;
}
   void set_y (int n)
{
y = n;
}
   double surface ()
{
double s;
s = x * y;
if (s < 0) s = -s;
return s;
}
};

int main ()
{
vector a;

a.set_x (3);
a.set_y (4);

cout << “Поверхность а: ” << a.surface() << endl;

return 0;
}

 

Вывод
Поверхность а: 12

 



Приведенный выше пример является немного странным , так как класс data x и у могут быть установлены , но они не могут быть прочитаны. Любая попытка в функции Main () ,чтобы прочитать a.x или a.y приведет к ошибке компиляции. В следующем примере, х и у могут быть прочитаны:

using namespace std;
#include <iostream>

class vector
{
protected:

double x;
double y;

public:

void set_x (int n)
{
x = n;
}   void set_y (int n)
{
y = n;
}

double get_x ()
{
return x;
}   double get_y ()
{
return y;
}
   double surface ()
{
double s;
s = x * y;
if (s < 0) s = -s;
return s;
}
};

int main ()
{
vector a;

a.set_x (3);
a.set_y (4);

cout << “Поверхность а: ” << a.surface() << endl;
cout << “Ширина а: ” << a.get_x() << endl;
cout << “Высота а: ” << a.get_y() << endl;

return 0;
}

 

Вывод
Поверхность а: 12 
Ширина а: 3
 
Высота а: 4

 



В C ++, один не должен получить доступ к данным класса напрямую. Методы должны быть объявлены. Почему это? Существует много причин. Во- первых, это позволяет изменить способ данные представлены в классе. Еще одна причина, это позволяет передавать данные внутри класса кросс-зависимыми (cross-dependent). Пусть х и у должны быть всегда одного и того же знака, в противном случае уродливые вещи могут случиться … Если разрешен доступ к данным класса непосредственно, было бы легко наложить сказать положительные х и отрицательный у. В приведенном ниже примере, это строго контролируется:

using namespace std;
#include <iostream>

int sign (double n)
{
if (n >= 0) return 1;
return -1;
}

class vector
{
protected:

double x;
double y;

public:

void set_x (int n)
{
x = n;
if (sign (x) != sign(y)) y = -y;
}   void set_y (int n)
{
y = n;
if (sign (y) != sign(x)) x = -x;
}

double get_x ()
{
return x;
}   double get_y ()
{
return y;
}
   double surface ()
{
double s;
s = x * y;
if (s < 0) s = -s;
return s;
}
};

int main ()
{
vector a;

a.set_x (-3);
a.set_y (4);

cout << ” Поверхность а: 12 ” << a.surface() << endl;
cout << ” Ширина а: ” << a.get_x() << endl;
cout << ” Высота а: ” << a.get_y() << endl;

return 0;
}

 

Вывод
Поверхность а: 12 
Ширина а: 3
 
Высота а: 4

 

31.

Давайте поговорим о ввода / вывода.В C ++ это очень обширная тема.Вот это программа, которая записывает в файл:

using namespace std;
#include <iostream>
#include <fstream>

int main ()
{
fstream f;

f.open(“test.txt”, ios::out);

f << “Это текстовый вывод в файл.<< endl;

double a = 345;

f  << “Число: ” << a << endl;

f.close();

return 0;
}

 

Содержание файла test.txt
Это текстовый вывод в файл. 
Число: 345

 

 

Вот это программа, которая читает из файла:

using namespace std;
#include <iostream>
#include <fstream>

int main ()
{
fstream f;
char c;

cout << “Что внутри файла test.txt” << endl;
cout << endl;

f.open(“test.txt”, ios::in);

while (! f.eof() )
{
f.get(c);                          // или c = f.get()
cout << c;
}

f.close();

return 0;
}

 

 

Вывод
Это текстовый вывод в файл. 
Число
: 345

 

32.

Вот это программа, которая записывает в символьный массив:

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

using namespace std;
#include <iostream>
#include <strstream>
#include <cstring>
#include <cmath>

int main ()
{
char a[1024];
ostrstream b(a, 1024);

b.seekp(0);                           // Начать с первого символа.
b << “2 + 2 = ” << 2 + 2 << ends;     // ( ends, not endl )
// ends просто
// нулевой символ ‘\0’
cout << a << endl;

double v = 2;

strcpy (a, “A синус:”);

b.seekp(strlen (a));
b << “sin (” << v << “) = ” << sin(v) << ends;

cout << a << endl;

return 0;
}

 

Вывод
2 + 2 = 4
A синус: sin (2) = 0.909297

 

 

Программа, которая считывает данные из строки символов:

using namespace std;
#include <iostream>
#include <strstream>
#include <cstring>

int main ()
{
char a[1024];
istrstream b(a, 1024);

strcpy (a, “45.656”);

double k, p;

b.seekg(0);                       // Начинаем с первого символа.
b >> k;

k = k + 1;

cout << k << endl;

strcpy (a, “444.23 56.89”);

b.seekg(0);
b >> k >> p;

cout << k << “, ” << p + 1 << endl;

return 0;
}

 

Вывод
46,656
444,23, 57,89

 

33.

Эта программа выполняет форматированный вывод двумя различными способами.Пожалуйста , обратите внимание на width() и setw() МОДИФИКАТОРЫ действуют только на следующей выводного элемента к потоку. На последующие пункты не будут влиять.

using namespace std;
#include <iostream>
#include <iomanip>

int main ()
{
int i;

cout << “Список номеров:” << endl;
for (i = 1; i <= 1024; i *= 2)
{
cout.width (7);
cout << i << endl;
}

cout << “Таблица чисел:” << endl;
for (i = 0; i <= 4; i++)
{
cout << setw(3) << i << setw(5) << i * i * i << endl;
}

return 0;
}

 

Вывод
Список номеров:
1
2
4
8
16
32
64
128
256
512
1024
Таблица чисел:
0 0
1 1
2 8
3 27
4 64

 

 

Теперь у вас есть базовые знания о C ++. В хороших книгах Вы изучите еще много вещей. Система управления файлами является очень мощным, он имеет много других возможностей , чем показаны здесь. Существует также много больше , чтобы сказать о классах: шаблонных классов (template classes), виртуальных классов (virtual classes)…

Для того, чтобы эффективно работать с C ++ , вам понадобится хороший справочник, так же, как вам нужен для C. Вам также потребуется информация о том , как C ++ используется в конкретной области деятельности. Стандарты, глобальный подход, трюки, типичные проблемы, с которыми сталкиваются и пути их решения … Лучший справочник, конечно, книги, написанные самим Бьерн Страуструп (я не помню , какой из них я читал). Следующая книга содержит почти все детали о C и C ++, он построен по аналогии с этим текстом , и он содержит в CD:

Jamsa’s C/C++ Programmer’s Bible
&copyright; 1998 Jamsa Press
Las Vegas, United States

Французский выпуск:
C/C++ La Bible du programmeur
Kris Jamsa, Ph.D – Lars Klander
France : Editions Eyrolles
www.eyrolles.com
Canada : Les Editions Reynald Goulet inc.
www.goulet.ca
ISBN 2-212-09058-7

Он считается устаревшим и сейчас:
Jamsa’s C/C++/C# Programmer’s Bible
Onword Press

Другие ссылки:

accu:  www.accu.org/bookreviews/public/reviews/0hr/index.htm

CoderSource.net:  www.codersource.net/

C++ Guide:  google-styleguide.googlecode.com/svn/trunk/cppguide.xml

C++ Reference: fresh2refresh.com/c/c-language-history

A similar tutorial for Ada is available at  www.adahome.com/Ammo/cpp2ada.html

A Haskell tutorial by a C programmer:  learnyouahaskell.com
Я хотел бы поблагодарить Didier Bizzarri, Toni Ronkko, Frédéric Cloth, Jack Lam, Morten Brix Pedersen, Elmer Fittery, Ana Yuseepi, William L. Dye, Bahjat F. Qaqish, Muthukumar Veluswamy, Marco Cimarosti, Jarrod Miller, Nikolaos Pothitos, Ralph Wu, Dave Abercrombie, Alex Pennington, Scott Marsden, Robert Krten, Dave Panter, Cihat Imamoglu, Bohdan Zograf, David L. Markowitz, Marko Pozner, Filip Zaludek and Kevin Wheeler за их вдохновение, советы, помощь, данных, сообщений об ошибках, ссылки, повышение английской редакции и перевода.

 

Eric Brasseur – c 23 февраля 1998 г. по 4 июня 2014 года

 

Источник: http://www.4p8.com/eric.brasseur/cppcen.html

Вернуться на главную страницу

Posted on

Leave a Reply