Adds complete translation

This commit is contained in:
Bohdan Shtepan 2015-12-05 16:07:14 +02:00
parent 83f3d7dc3b
commit aad2d2b6f2

View File

@ -162,7 +162,7 @@ void foo()
int main() int main()
{ {
// Включает все функци с пространства имен Second в текущую область видиомти. // Включает все функци с пространства имен Second в текущую область видимости.
// Обратите внимание, что простой вызов foo() больше не работает, // Обратите внимание, что простой вызов foo() больше не работает,
// так как теперь не ясно вызываем ли мы foo с пространства имен Second или // так как теперь не ясно вызываем ли мы foo с пространства имен Second или
// из глобальной области видимости. // из глобальной области видимости.
@ -177,26 +177,26 @@ int main()
// Ввод/Вывод // Ввод/Вывод
/////////////// ///////////////
// C++ input and output uses streams // Вводи и вывод в C++ использует потоки
// cin, cout, and cerr represent stdin, stdout, and stderr. // cin, cout и cerr предоставлнеы методами stdin, stdout и stderr.
// << is the insertion operator and >> is the extraction operator. // << - оператор вставки, >> - оператор извлечения.
#include <iostream> // Include for I/O streams #include <iostream> // Включение файла для работы с потоками Ввода\Вывода.
using namespace std; // Streams are in the std namespace (standard library) using namespace std; // Потоки доступны в пространстве имен std (стандартная библиотека)
int main() int main()
{ {
int myInt; int myInt;
// Prints to stdout (or terminal/screen) // Выводит stdout (или терминал\экран)
cout << "Enter your favorite number:\n"; cout << "Enter your favorite number:\n";
// Takes in input // Принимает ввод
cin >> myInt; cin >> myInt;
// cout can also be formatted // cout может принимать форматирование
cout << "Your favorite number is " << myInt << "\n"; cout << "Your favorite number is " << myInt << "\n";
// prints "Your favorite number is <myInt>" // напечатает "Your favorite number is <myInt>"
cerr << "Used for error messages"; cerr << "Used for error messages";
} }
@ -205,35 +205,35 @@ int main()
// Строки // Строки
////////// //////////
// Strings in C++ are objects and have many member functions // Строки в C++ являются объектами и имеют много функций-членов.
#include <string> #include <string>
using namespace std; // Strings are also in the namespace std (standard library) using namespace std; // Строки также доступны в пространстве имен std (стандартная библиотек)
string myString = "Hello"; string myString = "Hello";
string myOtherString = " World"; string myOtherString = " World";
// + is used for concatenation. // + используется для конкатенации строк.
cout << myString + myOtherString; // "Hello World" cout << myString + myOtherString; // "Hello World"
cout << myString + " You"; // "Hello You" cout << myString + " You"; // "Hello You"
// C++ strings are mutable and have value semantics. // Строки в C++ могут изменяться и имеют семантику значений.
myString.append(" Dog"); myString.append(" Dog");
cout << myString; // "Hello Dog" cout << myString; // "Hello Dog"
///////////// /////////////
// References // Ссылки
///////////// /////////////
// In addition to pointers like the ones in C, // В добавок к указателям доступных в C,
// C++ has _references_. // C++ имеет _ссылки_.
// These are pointer types that cannot be reassigned once set // Это такой тип указателя, который не может быть переназначен после инициализации
// and cannot be null. // и не может иметь значения null.
// They also have the same syntax as the variable itself: // Ссылки имеют схожий с переменными синтаксис:
// No * is needed for dereferencing and // * больше не используется для разыменования и
// & (address of) is not used for assignment. // & (адрес) не используется для назначения.
using namespace std; using namespace std;
@ -241,84 +241,80 @@ string foo = "I am foo";
string bar = "I am bar"; string bar = "I am bar";
string& fooRef = foo; // This creates a reference to foo. string& fooRef = foo; // Здесь создается указатель на foo.
fooRef += ". Hi!"; // Modifies foo through the reference fooRef += ". Hi!"; // Изменяет foo по ссылке
cout << fooRef; // Prints "I am foo. Hi!" cout << fooRef; // Печатает "I am foo. Hi!"
// Doesn't reassign "fooRef". This is the same as "foo = bar", and // Не переназначает "fooRef". Это тоже самое как "foo = bar", и
// foo == "I am bar" // foo == "I am bar"
// after this line. // после этой строчки.
cout << &fooRef << endl; //Prints the address of foo cout << &fooRef << endl; // Печатает адрес foo
fooRef = bar; fooRef = bar;
cout << &fooRef << endl; //Still prints the address of foo cout << &fooRef << endl; // По-прежнему печатает адрес foo
cout << fooRef; // Prints "I am bar" cout << fooRef; // Печатает "I am bar"
//The address of fooRef remains the same, i.e. it is still referring to foo. // Адрес fooRef остается тем же, то есть он по-прежнему ссылается на foo.
const string& barRef = bar; // Create a const reference to bar. const string& barRef = bar; // Создает const со ссылкой на bar.
// Like C, const values (and pointers and references) cannot be modified. // Также как и C, значения const (и указателей и ссылок) не могут быть изменены.
barRef += ". Hi!"; // Error, const references cannot be modified. barRef += ". Hi!"; // Ошибка, указатель const не может быть изменен.
// Sidetrack: Before we talk more about references, we must introduce a concept // Обходной путь: Прежде чем мы рассмотрим указатели более детально, нам нужно ознакомится
// called a temporary object. Suppose we have the following code: // с концепцией известной как "временный объект". Представьте, что мы имеем следующий код
string tempObjectFun() { ... } string tempObjectFun() { ... }
string retVal = tempObjectFun(); string retVal = tempObjectFun();
// What happens in the second line is actually: // Вот что на самом деле происходит во второй строе:
// - a string object is returned from tempObjectFun // - tempObjectFun возвращает строковый объект
// - a new string is constructed with the returned object as argument to the // - с возвращаемого объекта создается новая строка в качестве аргумента конструктору
// constructor // - возвращаемый объект уничтожается
// - the returned object is destroyed // Возвращаемый объект называется временным объектом. Временные объекты создаются
// The returned object is called a temporary object. Temporary objects are // когда функция возвращает объект, и уничтожаются в конце выполнения обрамляющего
// created whenever a function returns an object, and they are destroyed at the // выражения (По крайней мере, так это описывает спецификация, хотя компиляторы могут
// end of the evaluation of the enclosing expression (Well, this is what the // изменять это поведение. Для более подробной информации смотрите "оптимизация
// standard says, but compilers are allowed to change this behavior. Look up // возвращаемого значения". Таким образом в этом коде:
// "return value optimization" if you're into this kind of details). So in this
// code:
foo(bar(tempObjectFun())) foo(bar(tempObjectFun()))
// assuming foo and bar exist, the object returned from tempObjectFun is // предполагая, что foo и bar существуют, объект возвращаемый tempObjectFun передается
// passed to bar, and it is destroyed before foo is called. // в bar, и уничтожается перед вызовом foo.
// Now back to references. The exception to the "at the end of the enclosing // Возвращаемся к указателям. Исключением для правила "в конце выполнения обрамляющего
// expression" rule is if a temporary object is bound to a const reference, in // выражения" является временный объект привязанный к ссылке const, в этом случае
// which case its life gets extended to the current scope: // его жизненный цикл продлевается до текущей области видимости:
void constReferenceTempObjectFun() { void constReferenceTempObjectFun() {
// constRef gets the temporary object, and it is valid until the end of this // constRef получает временный объект, и он действителен до конца этой функции.
// function.
const string& constRef = tempObjectFun(); const string& constRef = tempObjectFun();
... ...
} }
// Another kind of reference introduced in C++11 is specifically for temporary // В C++11 предоставлен еще один тип ссылок специально для временных объектов.
// objects. You cannot have a variable of its type, but it takes precedence in // objects. Вы не можете объявить переменную этого типа, но он имеет приоритет в
// overload resolution: // в резолюции перегрузки:
void someFun(string& s) { ... } // Regular reference void someFun(string& s) { ... } // Обычная ссылка
void someFun(string&& s) { ... } // Reference to temporary object void someFun(string&& s) { ... } // Ссылка на временный объект
string foo; string foo;
someFun(foo); // Calls the version with regular reference someFun(foo); // Выполняет версию с обычной ссылкой
someFun(tempObjectFun()); // Calls the version with temporary reference someFun(tempObjectFun()); // Выполняет версию с временной ссылкой.
// For example, you will see these two versions of constructors for // Например, существуют следующие две версии конструктора std::basic_string:
// std::basic_string:
basic_string(const basic_string& other); basic_string(const basic_string& other);
basic_string(basic_string&& other); basic_string(basic_string&& other);
// Idea being if we are constructing a new string from a temporary object (which // Идея в том, если мы конструируем новую строку из временного объекта (который
// is going to be destroyed soon anyway), we can have a more efficient // так или иначе будет уничтожен), мы можем использовать более эффективный конструктор,
// constructor that "salvages" parts of that temporary string. You will see this // который "спасает" части этой временной строки. Эта концепция была названа
// concept referred to as "move semantics". // "move semantics".
///////////////////// /////////////////////
// Enums // Перечисления
///////////////////// /////////////////////
// Enums are a way to assign a value to a constant most commonly used for // Перечисления - способ объявления констант и установки их значений в основном
// easier visualization and reading of code // использующийся для упрощения чтения кода.
enum ECarTypes enum ECarTypes
{ {
Sedan, Sedan,
@ -332,9 +328,9 @@ ECarTypes GetPreferredCarType()
return ECarTypes::Hatchback; return ECarTypes::Hatchback;
} }
// As of C++11 there is an easy way to assign a type to the enum which can be // На момент выхода C++11 есть простой способ назначения типа перечисления, что
// useful in serialization of data and converting enums back-and-forth between // полезно в случае сериализации данных и преобразований между конечным типом и
// the desired type and their respective constants // соответствующими константами.
enum ECarTypes : uint8_t enum ECarTypes : uint8_t
{ {
Sedan, // 0 Sedan, // 0
@ -345,18 +341,19 @@ enum ECarTypes : uint8_t
void WriteByteToFile(uint8_t InputValue) void WriteByteToFile(uint8_t InputValue)
{ {
// Serialize the InputValue to a file // Сериализуем InputValue в файл
} }
void WritePreferredCarTypeToFile(ECarTypes InputCarType) void WritePreferredCarTypeToFile(ECarTypes InputCarType)
{ {
// The enum is implicitly converted to a uint8_t due to its declared enum type // Перечисление неявно преобразуется в uint8_t из-за раннее объявленного
// типа перечисления.
WriteByteToFile(InputCarType); WriteByteToFile(InputCarType);
} }
// On the other hand you may not want enums to be accidentally cast to an integer // С другой стороны, чтобы избежать случайного приведения к целочисленному типу или
// type or to other enums so it is instead possible to create an enum class which // другому перечислению, вы можете создать класс перечисления, который не будет
// won't be implicitly converted // преобразовываться неявно.
enum class ECarTypes : uint8_t enum class ECarTypes : uint8_t
{ {
Sedan, // 0 Sedan, // 0
@ -367,78 +364,78 @@ enum class ECarTypes : uint8_t
void WriteByteToFile(uint8_t InputValue) void WriteByteToFile(uint8_t InputValue)
{ {
// Serialize the InputValue to a file // Сериализуем InputValue в файл
} }
void WritePreferredCarTypeToFile(ECarTypes InputCarType) void WritePreferredCarTypeToFile(ECarTypes InputCarType)
{ {
// Won't compile even though ECarTypes is a uint8_t due to the enum // Хотя ECarTypes имеет тип uint8_t, код не будет скомпилирован из-за того,
// being declared as an "enum class"! // что перечисление было объявлено как класс перечисления.
WriteByteToFile(InputCarType); WriteByteToFile(InputCarType);
} }
////////////////////////////////////////// //////////////////////////////////////////
// Classes and object-oriented programming // Классы и объектно-ориентированное программирование
////////////////////////////////////////// //////////////////////////////////////////
// First example of classes // Пример классов
#include <iostream> #include <iostream>
// Declare a class. // Объявление класса.
// Classes are usually declared in header (.h or .hpp) files. // Обычно классы объявляют в заголовочном (.h или .hpp) файле.
class Dog { class Dog {
// Member variables and functions are private by default. // Переменный-члены и функции являются частными по умолчанию.
std::string name; std::string name;
int weight; int weight;
// All members following this are public // Все члены после этой сроки являются открытыми
// until "private:" or "protected:" is found. // пока "private:" или "protected:" не будет объявлено.
public: public:
// Default constructor // Конструктор по умолчанию
Dog(); Dog();
// Member function declarations (implementations to follow) // Объявление функций-членов
// Note that we use std::string here instead of placing // Обратите внимание, мы используем std::string здесь вместо использования
// using namespace std; // using namespace std;
// above. // выше.
// Never put a "using namespace" statement in a header. // Никогда не размещайте выражение "using namespace" в заголовке.
void setName(const std::string& dogsName); void setName(const std::string& dogsName);
void setWeight(int dogsWeight); void setWeight(int dogsWeight);
// Functions that do not modify the state of the object // Функции, которые не изменяют состояние объекта,
// should be marked as const. // должны быть помечены как const.
// This allows you to call them if given a const reference to the object. // Это позволяет вызывать их если дана const ссылка на объект.
// Also note the functions must be explicitly declared as _virtual_ // Обратите внимание, функции должны быть явно объявлены как _virtual_
// in order to be overridden in derived classes. // если вы хотите перегрузить их в производных классах.
// Functions are not virtual by default for performance reasons. // Функции не являются виртуальными по умолчания для повышения производительности.
virtual void print() const; virtual void print() const;
// Functions can also be defined inside the class body. // Такде функции могут быть определены внутри тела класса.
// Functions defined as such are automatically inlined. // Функции, определенные следующим образом, автоматически встроены.
void bark() const { std::cout << name << " barks!\n"; } void bark() const { std::cout << name << " barks!\n"; }
// Along with constructors, C++ provides destructors. // Наряду с конструкторами, в C++ есть деструкторы.
// These are called when an object is deleted or falls out of scope. // Они вызываются, когда объект удаляется или выпадает с области видимости.
// This enables powerful paradigms such as RAII // Это активирует мощную парадигму программирования известную как RAII
// (see below) // (смотрите ниже)
// The destructor should be virtual if a class is to be derived from; // Деструктор должен быть виртуальным, если класс будет производным.
// if it is not virtual, then the derived class' destructor will // Если он не виртуальный, тогда деструктор производного класса не будет вызван
// not be called if the object is destroyed through a base-class reference // если объект удален по ссылке или указателю базового класса.
// or pointer. // or pointer.
virtual ~Dog(); virtual ~Dog();
}; // A semicolon must follow the class definition. }; // Определение класса должно завершатся точкой с запятой.
// Class member functions are usually implemented in .cpp files. // Функции-члены класса, как правило, реализуются в .cpp файлах.
Dog::Dog() Dog::Dog()
{ {
std::cout << "A dog has been constructed\n"; std::cout << "A dog has been constructed\n";
} }
// Objects (such as strings) should be passed by reference // Объекты (такие как строки) должны передаваться по ссылке если вы будете
// if you are modifying them or const reference if you are not. // изменять их, или const-ссылке если нет.
void Dog::setName(const std::string& dogsName) void Dog::setName(const std::string& dogsName)
{ {
name = dogsName; name = dogsName;
@ -449,7 +446,7 @@ void Dog::setWeight(int dogsWeight)
weight = dogsWeight; weight = dogsWeight;
} }
// Notice that "virtual" is only needed in the declaration, not the definition. // Обратите внимание, "virtual" требуется только в объявлении, не в определении.
void Dog::print() const void Dog::print() const
{ {
std::cout << "Dog is " << name << " and weighs " << weight << "kg\n"; std::cout << "Dog is " << name << " and weighs " << weight << "kg\n";
@ -461,35 +458,34 @@ Dog::~Dog()
} }
int main() { int main() {
Dog myDog; // prints "A dog has been constructed" Dog myDog; // Печатает "A dog has been constructed"
myDog.setName("Barkley"); myDog.setName("Barkley");
myDog.setWeight(10); myDog.setWeight(10);
myDog.print(); // prints "Dog is Barkley and weighs 10 kg" myDog.print(); // Печатает "Dog is Barkley and weighs 10 kg"
return 0; return 0;
} // prints "Goodbye Barkley" } // Печатает "Goodbye Barkley"
// Inheritance: // Интерфейсы:
// This class inherits everything public and protected from the Dog class // Этот класс наследует все открытые и защищенные члены класса Dog
// as well as private but may not directly access private members/methods // также как и все закрытые, но не может непосредственно получить доступ к закрытым
// without a public or protected method for doing so // членам\методам без открытых или защищенных методов для этого.
class OwnedDog : public Dog { class OwnedDog : public Dog {
void setOwner(const std::string& dogsOwner); void setOwner(const std::string& dogsOwner);
// Override the behavior of the print function for all OwnedDogs. See // Переопределяем поведение функции печати для всех OwnedDog. Смотрите
// http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping // https://goo.gl/3kuH2x для боле общего введения, если вы не знакомы
// for a more general introduction if you are unfamiliar with // с концепцией полиморфизма подтипов (включения).
// subtype polymorphism. // Ключевое слово override является необязательным, но указывает что метод
// The override keyword is optional but makes sure you are actually // на самом деле перегружается в базовом классе.
// overriding the method in a base class.
void print() const override; void print() const override;
private: private:
std::string owner; std::string owner;
}; };
// Meanwhile, in the corresponding .cpp file: // Тем временем, в соответствующем .cpp файле:
void OwnedDog::setOwner(const std::string& dogsOwner) void OwnedDog::setOwner(const std::string& dogsOwner)
{ {
@ -498,53 +494,54 @@ void OwnedDog::setOwner(const std::string& dogsOwner)
void OwnedDog::print() const void OwnedDog::print() const
{ {
Dog::print(); // Call the print function in the base Dog class Dog::print(); // Вызывает функцию print в базовом классе Dog
std::cout << "Dog is owned by " << owner << "\n"; std::cout << "Dog is owned by " << owner << "\n";
// Prints "Dog is <name> and weights <weight>" // Печатает "Dog is <name> and weights <weight>"
// "Dog is owned by <owner>" // "Dog is owned by <owner>"
} }
////////////////////////////////////////// //////////////////////////////////////////
// Initialization and Operator Overloading // Инициализация и перегрузка операторов.
////////////////////////////////////////// //////////////////////////////////////////
// In C++ you can overload the behavior of operators such as +, -, *, /, etc. // В C++ вы можете перегрузить поведение таких операторов: +, -, *, / и др..
// This is done by defining a function which is called // Это делается путем определения функции, которая вызывается,
// whenever the operator is used. // когда используется оператор.
#include <iostream> #include <iostream>
using namespace std; using namespace std;
class Point { class Point {
public: public:
// Member variables can be given default values in this manner. // Значения по умолчанию для переменных-членов могут быть установлены
// следующим образом.
double x = 0; double x = 0;
double y = 0; double y = 0;
// Define a default constructor which does nothing // Определяем новый конструктор, который инициализирует Point со значениями
// but initialize the Point to the default value (0, 0) // по умолчанию (0, 0)
Point() { }; Point() { };
// The following syntax is known as an initialization list // Следующий синтаксис известен как список инициализации и является верным способом
// and is the proper way to initialize class member values // инициализировать значения членов класса.
Point (double a, double b) : Point (double a, double b) :
x(a), x(a),
y(b) y(b)
{ /* Do nothing except initialize the values */ } { /* Ничего не делайте кроме инициализации значений */ }
// Overload the + operator. // Перегружаем оперот +.
Point operator+(const Point& rhs) const; Point operator+(const Point& rhs) const;
// Overload the += operator // Перегружаем оператор +=.
Point& operator+=(const Point& rhs); Point& operator+=(const Point& rhs);
// It would also make sense to add the - and -= operators, // Имеет смысл добавить перегрузку операторов - и -=,
// but we will skip those for brevity. // но для краткости мы опустим эти детали.
}; };
Point Point::operator+(const Point& rhs) const Point Point::operator+(const Point& rhs) const
{ {
// Create a new point that is the sum of this one and rhs. // Создает новую точку, которая является суммой этой точки и rhs.
return Point(x + rhs.x, y + rhs.y); return Point(x + rhs.x, y + rhs.y);
} }
@ -558,59 +555,58 @@ Point& Point::operator+=(const Point& rhs)
int main () { int main () {
Point up (0,1); Point up (0,1);
Point right (1,0); Point right (1,0);
// This calls the Point + operator // Здесь происходит вызов оператора + класса Point
// Point up calls the + (function) with right as its parameter // Точка "up" вызывает + (функция) с параметром "right"
Point result = up + right; Point result = up + right;
// Prints "Result is upright (1,1)" // Печатает "Result is upright (1,1)"
cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; cout << "Result is upright (" << result.x << ',' << result.y << ")\n";
return 0; return 0;
} }
///////////////////// /////////////////////
// Templates // Шаблоны
///////////////////// /////////////////////
// Templates in C++ are mostly used for generic programming, though they are // Шаблоны в С++, в основном, используются для обобщенного программирования, хотя
// much more powerful than generic constructs in other languages. They also // они гораздо более мощны чем дженерики в других языках. Они также поддерживают
// support explicit and partial specialization and functional-style type // явные, частные и функциональные типы классов; на самом деле, они являются
// classes; in fact, they are a Turing-complete functional language embedded // тьюринг-полным языком встроенным в C++!
// in C++!
// We start with the kind of generic programming you might be familiar with. To // Мы начнем с наиболее распространенного типа обобщенного программирования. Чтобы
// define a class or function that takes a type parameter: // определить класс или функцию, которая принимает параметр типа:
template<class T> template<class T>
class Box { class Box {
public: public:
// In this class, T can be used as any other type. // В этом классе T может быть любого типа.
void insert(const T&) { ... } void insert(const T&) { ... }
}; };
// During compilation, the compiler actually generates copies of each template // Во время компиляции, компилятор фактически генерирует копии каждого шаблона
// with parameters substituted, so the full definition of the class must be // с замещенными параметрами, по-этому полное определение класса должно присутствовать
// present at each invocation. This is why you will see template classes defined // при каждом вызове. Именно по-этому классы шаблонов полностью определены в
// entirely in header files. // заголовочных файлах.
// To instantiate a template class on the stack: // Чтобы создать экземпляр класса шаблона на стеке:
Box<int> intBox; Box<int> intBox;
// and you can use it as you would expect: // и вы можете использовать его, как и ожидалось:
intBox.insert(123); intBox.insert(123);
// You can, of course, nest templates: // Вы, конечно, можете использовать вложенные шаблоны:
Box<Box<int> > boxOfBox; Box<Box<int> > boxOfBox;
boxOfBox.insert(intBox); boxOfBox.insert(intBox);
// Until C++11, you had to place a space between the two '>'s, otherwise '>>' // Вплоть до С++11, вы должны были ставить пробел между двумя символами '>', иначе '>>'
// would be parsed as the right shift operator. // принимался парсером, как оператор правого сдвига.
// You will sometimes see // Иногда вы можете увидеть
// template<typename T> // template<typename T>
// instead. The 'class' keyword and 'typename' keywords are _mostly_ // вместо этого. В этом случае, ключевые слова 'class' и 'typename' _в основном_
// interchangeable in this case. For the full explanation, see // взаимозаменяемыми. Для более подробной информации смотрите
// http://en.wikipedia.org/wiki/Typename // http://en.wikipedia.org/wiki/Typename
// (yes, that keyword has its own Wikipedia page). // (да-да, это ключевое слово имеет собственную страничку на вики).
// Similarly, a template function: // Аналогичным образом, шаблонная функция:
template<class T> template<class T>
void barkThreeTimes(const T& input) void barkThreeTimes(const T& input)
{ {
@ -619,115 +615,115 @@ void barkThreeTimes(const T& input)
input.bark(); input.bark();
} }
// Notice that nothing is specified about the type parameters here. The compiler // Обратите внимание, что здесь ничего не указано о типе параметра. Компилятор
// will generate and then type-check every invocation of the template, so the // будет генерировать и затем проверять тип каждый вызов шаблона, по-этому
// above function works with any type 'T' that has a const 'bark' method! // данная функция работает с любым типом 'T', который имеет метод 'bark'.
Dog fluffy; Dog fluffy;
fluffy.setName("Fluffy") fluffy.setName("Fluffy")
barkThreeTimes(fluffy); // Prints "Fluffy barks" three times. barkThreeTimes(fluffy); // Печатает "Fluffy barks" три раза.
// Template parameters don't have to be classes: //Параметры шаблона не должны быть классами:
template<int Y> template<int Y>
void printMessage() { void printMessage() {
cout << "Learn C++ in " << Y << " minutes!" << endl; cout << "Learn C++ in " << Y << " minutes!" << endl;
} }
// And you can explicitly specialize templates for more efficient code. Of // В конце концов, вы можете явно специализировать шаблоны для более эффективного
// course, most real-world uses of specialization are not as trivial as this. // кода. Конечно, большинство реальных случаев использования специализации
// Note that you still need to declare the function (or class) as a template // не так тривиально, как это. Обратите внимание, вам все еще нужно явно объявить
// even if you explicitly specified all parameters. // функцию (или класс) в качестве шаблона, даже если вы явно указали все параметры.
template<> template<>
void printMessage<10>() { void printMessage<10>() {
cout << "Learn C++ faster in only 10 minutes!" << endl; cout << "Learn C++ faster in only 10 minutes!" << endl;
} }
printMessage<20>(); // Prints "Learn C++ in 20 minutes!" printMessage<20>(); // Печатает "Learn C++ in 20 minutes!"
printMessage<10>(); // Prints "Learn C++ faster in only 10 minutes!" printMessage<10>(); // Печатает "Learn C++ faster in only 10 minutes!"
///////////////////// /////////////////////
// Exception Handling // Обработка исключений
///////////////////// /////////////////////
// The standard library provides a few exception types // Стандартная библиотека предоставляет несколько типов исключений
// (see http://en.cppreference.com/w/cpp/error/exception) // (смотрите http://en.cppreference.com/w/cpp/error/exception)
// but any type can be thrown an as exception // но, в принципе, любой тип может быть брошен в качестве исключения.
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
// All exceptions thrown inside the _try_ block can be caught by subsequent // Все исключения брошены внутри блока _try_ могут быть пойманы в последующем блоке
// _catch_ handlers. // _catch_.
try { try {
// Do not allocate exceptions on the heap using _new_. // Не выделяйте память в куче для исключений с помощью ключевого слова _new_.
throw std::runtime_error("A problem occurred"); throw std::runtime_error("A problem occurred");
} }
// Catch exceptions by const reference if they are objects // Поймайте исключение по константной ссылке, если они являются объектами
catch (const std::exception& ex) catch (const std::exception& ex)
{ {
std::cout << ex.what(); std::cout << ex.what();
} }
// Catches any exception not caught by previous _catch_ blocks // Ловит любое исключение не пойманное предыдущим блоком _catch_
catch (...) catch (...)
{ {
std::cout << "Unknown exception caught"; std::cout << "Unknown exception caught";
throw; // Re-throws the exception throw; // Повторный выброс исключения
} }
/////// ///////
// RAII // Получение ресурса есть инициализация (RAII)
/////// ///////
// RAII stands for "Resource Acquisition Is Initialization". // Программная идиома объектно-ориентированного программирования, смысл которой
// It is often considered the most powerful paradigm in C++ // заключается в том, что с помощью тех или иных программных механизмов получение
// and is the simple concept that a constructor for an object // некоторого ресурса неразрывно совмещается с инициализацией, а освобождение -
// acquires that object's resources and the destructor releases them. // с уничтожением объекта.
// To understand how this is useful, // Чтобы понять на сколько это полезно,
// consider a function that uses a C file handle: // рассмотрим функцию, которая использует обработчик файлов в С:
void doSomethingWithAFile(const char* filename) void doSomethingWithAFile(const char* filename)
{ {
// To begin with, assume nothing can fail. // Для начала, предположим, ничего не может потерпеть неудачу.
FILE* fh = fopen(filename, "r"); // Open the file in read mode. FILE* fh = fopen(filename, "r"); // Открываем файл в режиме чтения.
doSomethingWithTheFile(fh); doSomethingWithTheFile(fh);
doSomethingElseWithIt(fh); doSomethingElseWithIt(fh);
fclose(fh); // Close the file handle. fclose(fh); // Закрываем обработчик файла.
} }
// Unfortunately, things are quickly complicated by error handling. // К сожалению, вещи быстро осложняется обработкой ошибок.
// Suppose fopen can fail, and that doSomethingWithTheFile and // Предположим fopen может потерпеть неудачу, тогда doSomethingWithTheFile и
// doSomethingElseWithIt return error codes if they fail. // doSomethingElseWithIt вернут коды ошибок если потерпят неудачу.
// (Exceptions are the preferred way of handling failure, // (Исключения являются предпочтительным способом обработки ошибок,
// but some programmers, especially those with a C background, // но некоторые программисты, особенно те, кто имеет большой опыт работы с С,
// disagree on the utility of exceptions). // не согласны с аргументами о полезности исключений).
// We now have to check each call for failure and close the file handle // Теперь мы должны проверить каждый вызов на наличие ошибок и закрыть обработчик
// if a problem occurred. // файла если таковы есть.
bool doSomethingWithAFile(const char* filename) bool doSomethingWithAFile(const char* filename)
{ {
FILE* fh = fopen(filename, "r"); // Open the file in read mode FILE* fh = fopen(filename, "r"); // Открывает файл в режиме чтения
if (fh == nullptr) // The returned pointer is null on failure. if (fh == nullptr) // В случае неудачи возвращаемый указатель принимает null.
return false; // Report that failure to the caller. return false; // Сообщает об неудаче вызывающему.
// Assume each function returns false if it failed // Предположим, каждая функция возвращает false в случае неудачи
if (!doSomethingWithTheFile(fh)) { if (!doSomethingWithTheFile(fh)) {
fclose(fh); // Close the file handle so it doesn't leak. fclose(fh); // Закрываем обработчик файл чтобы не было утечек
return false; // Propagate the error. return false; // Сообщает об ошибке.
} }
if (!doSomethingElseWithIt(fh)) { if (!doSomethingElseWithIt(fh)) {
fclose(fh); // Close the file handle so it doesn't leak. fclose(fh); // Закрываем обработчик файл чтобы не было утечек
return false; // Propagate the error. return false; // Сообщает об ошибке.
} }
fclose(fh); // Close the file handle so it doesn't leak. fclose(fh); // Закрываем обработчик файл чтобы не было утечек
return true; // Indicate success return true; // Указывает на успех
} }
// C programmers often clean this up a little bit using goto: // C-программисты часто упорядочивают это с помощью goto:
bool doSomethingWithAFile(const char* filename) bool doSomethingWithAFile(const char* filename)
{ {
FILE* fh = fopen(filename, "r"); FILE* fh = fopen(filename, "r");
@ -741,18 +737,18 @@ bool doSomethingWithAFile(const char* filename)
goto failure; goto failure;
fclose(fh); // Close the file fclose(fh); // Close the file
return true; // Indicate success return true; // Указывает на успех
failure: failure:
fclose(fh); fclose(fh);
return false; // Propagate the error return false; // Сообщает об ошибке.
} }
// If the functions indicate errors using exceptions, // Если функции указывают на ошибки с помощью исключений, вещи становятся проще,
// things are a little cleaner, but still sub-optimal. // но все еще не оптимальны.
void doSomethingWithAFile(const char* filename) void doSomethingWithAFile(const char* filename)
{ {
FILE* fh = fopen(filename, "r"); // Open the file in read mode FILE* fh = fopen(filename, "r"); // Открываем файл в режиме чтения
if (fh == nullptr) if (fh == nullptr)
throw std::runtime_error("Could not open the file."); throw std::runtime_error("Could not open the file.");
@ -761,52 +757,51 @@ void doSomethingWithAFile(const char* filename)
doSomethingElseWithIt(fh); doSomethingElseWithIt(fh);
} }
catch (...) { catch (...) {
fclose(fh); // Be sure to close the file if an error occurs. fclose(fh); // Убедитесь, что закрываете файл, если происходит ошибка.
throw; // Then re-throw the exception. throw; // Затем повторно бросает исключение.
} }
fclose(fh); // Close the file fclose(fh); // Close the file
// Everything succeeded // Успех
} }
// Compare this to the use of C++'s file stream class (fstream) // Сравните это с использованием класса потока файла (fstream) в С++, который
// fstream uses its destructor to close the file. // использует свой деструктор чтобы закрыть файл. Еще раз взгляните выше,
// Recall from above that destructors are automatically called // деструктор вызывается автоматически, когда объект выпадает из области видимости.
// whenever an object falls out of scope.
void doSomethingWithAFile(const std::string& filename) void doSomethingWithAFile(const std::string& filename)
{ {
// ifstream is short for input file stream // ifstream определяет файловый поток
std::ifstream fh(filename); // Open the file std::ifstream fh(filename); // Открыть файл
// Do things with the file // Что-то делать с файлом
doSomethingWithTheFile(fh); doSomethingWithTheFile(fh);
doSomethingElseWithIt(fh); doSomethingElseWithIt(fh);
} // The file is automatically closed here by the destructor } // Здесь файл автоматически закрывается в деструкторе.
// This has _massive_ advantages: // Это имеет _огромнейшие_ преимущества:
// 1. No matter what happens, // 1. Неважно, что произойдет,
// the resource (in this case the file handle) will be cleaned up. // ресурсы (в данном случае обработчик файлов) будут очищены.
// Once you write the destructor correctly, // После того, как вы правильно напишите деструктор,
// It is _impossible_ to forget to close the handle and leak the resource. // Больше будет е возможно_ закрыть обработчик файлов или допустить утечку.
// 2. Note that the code is much cleaner. // 2. Обратите внимание, что код намного проще.
// The destructor handles closing the file behind the scenes // Деструктор закрывает файловый поток "за кулисами" и вам больше не нужно об
// without you having to worry about it. // этом беспокоится.
// 3. The code is exception safe. // 3. Код устойчив к исключениям.
// An exception can be thrown anywhere in the function and cleanup // Исключение может быть брошено в любом месте в функции и это никак не повлияет
// will still occur. // на очистку.
// All idiomatic C++ code uses RAII extensively for all resources. // Весь идиоматический код на С++ широко использует RAII для всех ресурсов.
// Additional examples include // Дополнительные примеры включат
// - Memory using unique_ptr and shared_ptr // - Использование памяти unique_ptr и shared_ptr
// - Containers - the standard library linked list, // - Контейнеры - стандартная библиотека связанных списков, векторы
// vector (i.e. self-resizing array), hash maps, and so on // (т.е. самоизменяемые массивы), хэш-карты и все остальное автоматически
// all automatically destroy their contents when they fall out of scope. // уничтожается сразу-же, когда выходит за пределы области видимости.
// - Mutexes using lock_guard and unique_lock // - Ипользование мютексов lock_guard и unique_lock
// containers with object keys of non-primitive values (custom classes) require // Контейнеры с пользовательскими классами в качестве ключей требуют
// compare function in the object itself or as a function pointer. Primitives // функций-компаратор в самом объекте или как указатель на функцию. Примитивы
// have default comparators, but you can override it. // имеют компараторы по умолчанию, но вы можете перегрузить их.
class Foo { class Foo {
public: public:
int j; int j;
@ -817,81 +812,82 @@ struct compareFunction {
return a.j < b.j; return a.j < b.j;
} }
}; };
//this isn't allowed (although it can vary depending on compiler) // это не допускается (хотя это может варьироваться в зависимости от компилятора)
//std::map<Foo, int> fooMap; // std::map<Foo, int> fooMap;
std::map<Foo, int, compareFunction> fooMap; std::map<Foo, int, compareFunction> fooMap;
fooMap[Foo(1)] = 1; fooMap[Foo(1)] = 1;
fooMap.find(Foo(1)); //true fooMap.find(Foo(1)); //true
///////////////////// /////////////////////
// Fun stuff // Веселые вещи
///////////////////// /////////////////////
// Aspects of C++ that may be surprising to newcomers (and even some veterans). // Аспекты С++, которые могут быть удивительными для новичком (и даже для некоторых
// This section is, unfortunately, wildly incomplete; C++ is one of the easiest // ветеранов). Этот раздел, к сожалению, очень неполон. С++ является одним из самых
// languages with which to shoot yourself in the foot. // простых языков, где очень легко выстрелить себе в ногу.
// You can override private methods! // Вы можете перегрузить приватные методы!
class Foo { class Foo {
virtual void bar(); virtual void bar();
}; };
class FooSub : public Foo { class FooSub : public Foo {
virtual void bar(); // Overrides Foo::bar! virtual void bar(); // Перегружает Foo::bar!
}; };
// 0 == false == NULL (most of the time)! // 0 == false == NULL (в основном)!
bool* pt = new bool; bool* pt = new bool;
*pt = 0; // Sets the value points by 'pt' to false. *pt = 0; // Устанавливает значение указателя 'pt' в false.
pt = 0; // Sets 'pt' to the null pointer. Both lines compile without warnings. pt = 0; // Устанавливает значение 'pt' в нулевой указатель. Обе линии проходят
// компиляцию без ошибок.
// nullptr is supposed to fix some of that issue: // nullptr приходит на помощь:
int* pt2 = new int; int* pt2 = new int;
*pt2 = nullptr; // Doesn't compile *pt2 = nullptr; // Не пройдет компиляцию
pt2 = nullptr; // Sets pt2 to null. pt2 = nullptr; // Устанавливает pt2 в null.
// There is an exception made for bools. // Существует исключение для булевых значений.
// This is to allow you to test for null pointers with if(!ptr), // Это позволит вам проверить указатели с помощью if(!ptr),
// but as a consequence you can assign nullptr to a bool directly! // но как следствие вы можете установить nullptr в bool напрямую!
*pt = nullptr; // This still compiles, even though '*pt' is a bool! *pt = nullptr; // Это по прежнему проходит компиляцию, даже если '*pt' - bool!
// '=' != '=' != '='! // '=' != '=' != '='!
// Calls Foo::Foo(const Foo&) or some variant (see move semantics) copy // Вызывает Foo::Foo(const Foo&) или некий вариант (смотрите "move semantics")
// constructor. // копирования конструктора.
Foo f2; Foo f2;
Foo f1 = f2; Foo f1 = f2;
// Calls Foo::Foo(const Foo&) or variant, but only copies the 'Foo' part of // Вызывает Foo::Foo(const Foo&) или вариант, но копирует только часть 'Foo' из
// 'fooSub'. Any extra members of 'fooSub' are discarded. This sometimes // 'fooSub'. Любые другие члены 'fooSub' пропускаются. Иногда это ужасное поведение
// horrifying behavior is called "object slicing." // называют "object slicing."
FooSub fooSub; FooSub fooSub;
Foo f1 = fooSub; Foo f1 = fooSub;
// Calls Foo::operator=(Foo&) or variant. // Вызывает Foo::operator=(Foo&) или вариант.
Foo f1; Foo f1;
f1 = f2; f1 = f2;
// How to truly clear a container: // Как по-настоящему очистить контейнер:
class Foo { ... }; class Foo { ... };
vector<Foo> v; vector<Foo> v;
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
v.push_back(Foo()); v.push_back(Foo());
// Following line sets size of v to 0, but destructors don't get called // В слудующей точке размер v устанавливается в 0, но деструктор не вызывается
// and resources aren't released! // и не происходит очистка ресурсов!
v.empty(); v.empty();
v.push_back(Foo()); // New value is copied into the first Foo we inserted v.push_back(Foo()); // Новые значения копируются в первый вставленный Foo
// Truly destroys all values in v. See section about temporary objects for // Настоящие уничтожение всех значений v. Смотрите раздел о временном объекте
// explanation of why this works. // для объяснения того, как это работает.
v.swap(vector<Foo>()); v.swap(vector<Foo>());
``` ```
Further Reading: Дальнейшее чтение:
An up-to-date language reference can be found at Наиболее полное и обновленное руководство по С++ можно найти на
<http://cppreference.com/w/cpp> <http://cppreference.com/w/cpp>
Additional resources may be found at <http://cplusplus.com> Дополнительные ресурсы могут быть найдены на <http://cplusplus.com>