Отличия языков программирования C и C++

Концепция языка C++

С++ — язык общего назначения и задуман для того, чтобы настоящие программисты получили удовольствие от самого процесса программирования.

Язык программирования С++ задумывался как язык, который будет:

За исключением второстепенных деталей, он практически содержит язык С как подмножество (хотя есть пример программы, которая является программой на языке C, но не может быть скомпилирована на языке C++). Язык С расширяется введением гибких и эффективных средств, предназначенных для построения новых типов. Программист структурирует свою задачу, определив новые типы, которые точно соответствуют понятиям предметной области задачи. Такой метод построения программы обычно называют абстракцией данных. Информация о типах содержится в некоторых объектах типов, определенных пользователем. С такими объектами можно работать надежно и просто даже в тех случаях, когда их тип нельзя установить на стадии трансляции. Программирование с использованием таких объектов обычно называют объектно-ориентированным. Если этот метод применяется правильно, то программы становятся короче и понятнее, а сопровождение их упрощается.

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

Как язык, так и стандартные библиотеки С++ проектировались в расчете на переносимость. Имеющиеся реализации языка будут работать в большинстве систем, поддерживающих С. В программах на С++ можно использовать библиотеки С. Большинство служебных программ, рассчитанных на С, можно использовать и в С++.

Можно сказать, что Си и С++ сосуществуют между собой. Когда в 2011 году вышел новый стандарт языка С++ — С++11, вместе с ним вышел и стандарт языка Си — С11.

Заголовочные файлы стандартной библиотеки C++

Все заголовочные файлы стандартной библиотеки языка C++ не содержат расширения .h. Например:

#include<iostream>
#include<vector>
#include<algorithm>

Заголовочные файлы из стандартной библиотеки языка C можно использовать в языке C++, но их имена изменились - в начало файла добавилась буква "c", а расширение ".h" исчезло. То есть при желании использовать функции, которые в языке C определены в заголовочных файлах stdio.h или math.h, их требуется подключать следующим образом:

#include<cstdio>
#include<cmath>

Стандартная библиотека C++

Язык C++ содержит обширную стандартную библиотеку.

Основные части библиотеки следующие:

  1. Ввод-вывод описан в заголовочных файлах iostream, fstream и других.
  2. Работа со строками описана в файле string и других.
  3. Контейнеры (структуры данных) описаны в большом числе заголовочных файлов в соответствии с типом контейнера. Например, vector - динамический массив, set - множество с возможностью быстрого добавления, удаления, поиска элементов, map - ассоциативный массив (словарь), list - двусвязный список, stack - стек, queue - очередь.
  4. Алгоритмы (линейный и двоичный поиск, нахождение следующей перестановки, случайная перестановка) описаны в заголовочном файле algorithm.

Первоначально часть стандартной библиотеки называлась STL - Standard Template Library и развивалась независимо от языка C++ компаниями HP и SGI. Затем она была добавлена в стандарт языка, но название STL сохранилось и часто употребляется применительно к той части библиотеки, которая относится к контейнерам и алгоритмам.

Пространства имен

Имена (функций, переменных) в языке C++ можно разделять на "пространства имен" для удобства - чтобы могли существовать функции и переменные с одинаковыми именами в разных "пространствах имен".

Пространство имен объявляется так:

namespace my_namespace
{
    // Описание функций, переменных, классов
    int var;
};

Для доступа к переменной var из пространства имен my_namespace нужно писать my_namespace::var. Можно также использовать инструкцию:

using namespace my_namespace;

тогда все имена из пространства имен my_namespace можно использовать без указания имени пространства имен (просто писать var).

Вся стандартная библиотека находится в пространстве имен std, поэтому нужно либо писать

std::cout << a << std::endl;

для вывода переменной a. Или написать в начале программы

using namespace std;

и тогда можно будет просто писать

cout << a << endl;

Ввод-вывод в языке C++

Для стандартного ввода-вывода в языке C++ используется заголовочный файл iostream.

В нем объявлены объекты cin для ввода с клавиатуры и cout для вывода на экран.

Чтобы считать со стандартного ввода значения переменных a, b, с, нужно написать:

std::cin >> a >> b >> c;

Для вывода на экран этих переменных нужно написать:

std::cout << a << b << с;

a

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

std::cout << a << " " << b << " " << c;

Типы переменных определяются автоматически благодаря технологии перегрузки операторов.

Чтобы вывести конец строки нужно вывести стандартный объект endl:

std::cout << std::endl;

Можно не писать std::, если дать инструкцию using namespace std в начале программы.

Комментарии в тексте программы

В языке C допускались только многострочные комментарии. Начало комментария обозначалось символами /*, конец - символами */.

Пример:

/* Это комментарий.
   он может занимать несколько строк */

В языке C++ появились однострочные комментарии - они отмечаются символами // и продолжаются до конца строки:

int n; // Размер считываемого массива 

Cсылки

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

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

  1. При объявлении ссылка обязательно  на уже существующий объект данного типа. Ссылка не может ссылаться "ни на что".
  2. Ссылка от её объявления до её исчезновения указывает на один и тот же адрес.
  3. При обращении к ссылке разыменование происходит автоматически.
  4. Адрес ссылки -- это адрес исходного объекта, на который она указывает.

Объявление ссылок очень похоже на объявление указателей, только вместо звёздочки * пишется амперсанд &.
При объявлении ссылка обязана быть инициализирована.

int &x; // недопустимо!
int &x = veryLongVariableName; // допустимо. Теперь x - это альтернативное имя переменной veryLongVariableName

int A[10];
int &x = A[5]; // Ссылка может указывать на элемент массива
x++;            // то же, что A[5]++;
x = 1;        // то же, что A[5] = 1;

Передача параметров в функцию по ссылке

Параметры можно передавать по ссылкам. При этом связывание ссылки с определённой переменной произойдёт в момент вызова функции (на этапе выполнения программы).

void foo(int &x)
{
  x = 3;
}
int main()
{
  int t = 1;
  foo (t);
  cout << t;  // выведет 3
}

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

void foo(const int &x);

Это гарантирует программисту-пользователю функции неизменность передаваемого значения.

Для типа int передача по константной ссылке обычно не нужна, так как можно просто передать аргумент по значению, но для большого класса или структуры передача по ссылке гораздо быстрее и экономит память.

Чего нельзя делать со ссылкой

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

Также синтаксис С++ не позволяет создавать указатели на ссылки и массивы ссылок.

Логический тип данных

В языке С++ для логических значений существует специальный тип -- bool.

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

Переменная типа bool занимает в памяти ровно 1 байт.

bool b;
cout << sizeof(b); //выведет 1

Допустимые операции

С логическими переменными можно осуществлять логические операции:

~x -- логическое отрицание (НЕ)

x & y -- логическое умножение (И)

x | y -- логические сложение (ИЛИ)

Для типа bool стираются различия между операторами && и &, а также между || и |.

Совместимость с типом int

Тип bool совместим с типом int по присваиванию в обе стороны.

При этом true переходит в 1, false -- в 0.

При обратном приведении любое число, не равное нулю -- переходит в true, 0 -- в false.

Если использовать bool в арифметическом выражении, то оно будет переведено в int: bool + bool = int.

Надо понимать, что в С++ логический и целочисленный тип -- это разные типы, поэтому по типу аргумента int и bool возможна перегрузка функций.

Значения по умолчанию для параметров функций

При объявлении функции можно назначить значение аргумента "по умолчанию". Если этот аргумент не будет задан, то функция будет использовать значение "по умолчанию).

Например:

int factorial(int n=0)

Если вызывать функцию без параметров, то значение параметра n будет равно 0.

"По умолчанию" можно передавать только последние параметры функции. Например, объявим функцию так:

void f(int x, int y=1, int z=2);

Эту функцию можно вызвать от одного, двух, или трех параметров. Если вызвать ее от одного параметра, то будет передано значение x, а значения y и z возьмутся "по умолчанию" и будут равны 1 и 2. Если вызвать от 2 параметров - то будут заданы значения x и y, а значение z будет равно 2.

const-объявления

В языке C для объявления констант использовались директивы препроцессора #define. Например:

#define N 100

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

#define N 1000

В языке C++ появились константные выражения, которые нужно использовать вместо #define:

const int N = 100;

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

Работа с динамической памятью

Для работы с динамической памятью вместо функций malloc и free языка C в языке C++ введены операторы new и delete. Использование функций языка C для работы с динамической памятью не рекомендуется в языке C++