Documente Academic
Documente Profesional
Documente Cultură
## General Information
All the statements that begin with a "#" are preprocessor statements. These are
processed before compiling.
Header files don't get compiled (unless they are included in an implementation
file).
Every implementation file gets compiled individually into an object file. Then, the
linker takes all the object files and it _glues_ them together into a single file
(_.dll_ or _.exe_).
## Preprocessor Statements
### · _#include_
Includes (literally copy-pastes) all the contents of the parameter file (typically,
a header file) to the current file.
Examples:
```cpp
#include <iostream>
#include "Log.h"
```
### · _#define_
Examples:
```cpp
#define PI 3.141592
#define INTEGER int
```
### · #if
Examples:
```cpp
#if 1
void foo() {}
#endif
```
```cpp
// Log.h file
#ifndef _LOG_H
#define _LOG_H
// ...
void Log(const char* message);
// ...
#endif
```
The main function doesn't need an explicit return statement, by default it returns
_0_.
```cpp
int main() {}
```
```cpp
int main(int argc, int* argv[]) {}
```
## Hello World
```cpp
#include <iostream>
int main() {
std::cout << "Hello, world!" << std::endl;
std::cin.get();
}
```
## [Data Types](https://en.cppreference.com/w/cpp/language/types)
If primitive type variables are not initialized, they will contain whatever was
left in their memory location.
- char : 1 byte
- wchar_t : 4 bytes (Win), 8 bytes (Linux)
- char8_t : 1 byte (UTF-8)
- char16_t : 4 bytes (UTF-16)
- char32_t : 8 bytes (UTF-32)
```cpp
char x = 5;
char c = 'w';
```
```cpp
short s(376);
int n{-13};
unsigned int n = 42;
long long = 1337;
```
- float (4 bytes)
- double (8 bytes)
- long double (10 bytes)
```cpp
float v = 5.3f;
double d = 9.33156;
```
```cpp
bool f = false; // 0
bool t = true; // anything other than 0
```
## Pointers
```cpp
int var = 8;
int* ptr = &var; // reference
*ptr = 10; // dereference
```cpp
char* buffer = new char[8]; // allocate an 8 byte buffer
memset(buffer, 0, 8); // fill the buffer with zeroes
char** ptr = &buffer; // pointer to a pointer
delete[] buffer; // deallocate
```
## References
A reference variable is just an alias. At compile time, only the original will be
kept.
```cpp
int x = 5;
int& ref = x;
```
```cpp
void Increment(int& val) {
val++;
}
int main() {
int x = 5;
Increment(x);
Log(x); // 6
AlsoIncrement(&x);
Log(x); // 7
}
```
```cpp
int a = 5;
int b = 8;
int& ref = a;
ref = b; // this doesn't change what 'ref' refers to, it will set 'a' to the value
of 'b' (8).
```
## Arrays
```cpp
int values[5]; // allocate memory to store 5 integers
values[2] = 87; // set the 3rd element
int third = values[2];
```
Because arrays are just pointers to the first element in the array, we can do the
following:
```cpp
int values[3] = { 0, 1, 2 }; // array with initialized values
int* ptr = values;
int third = values[2];
int alsoThird = *(ptr + 2); // add a 2*sizeof(int) byte offset
int otherThird = *(int*)((char*)ptr + 8); // to set an offset byte by byte, cast
the pointer to a single-byte type
```
```cpp
int values[5];
int count = sizeof(values) / sizeof(int); // 5
```
```cpp
class Entity {
static const int data_size = 5;
int data[data_size];
}
```
```cpp
int* arr = new int[5];
delete[] arr;
```
Arrays decay into pointers, but are not the exact same thing.
```cpp
char s[6] = "Hello";
PrintSomething(s);
PrintSomething(&s[0]); // compiler will treat it like this
// ...
void PrintSomething(char* ptr) {}
```
## Strings
String literals are immutable because they are stored in a read-only section of the
memory. They have a fixed size once assigned and are null-terminated.
```cpp
const char* str = "C-style string";
int n = strlen(str); // string length
```
Be aware that even if this looks like a normal array, is still an immutable string.
The compiler is creating a new variable with a modified copy of the string.
```cpp
char name[5] = { 'J', 'o', 'h', 'n', '\0' };
name[0] = 'j';
```
```cpp
#include <string>
// ...
std::string str = "C++ string";
int n = str.size(); // string length
```
#### Concatenation
Raw strings cannot be concatented because they have a fixed size, but
_std::string_-s have the _+_ operator overloaded to allow so.
```cpp
std::string str1 = "Hello";
str2 += ", world!";
std::string str2 = std::string("Hello") + ", world!";
```
Since C++14:
```cpp
#include <string>
using namespace std::string_literals;
// ...
std::string str1 = "Hello"s + ", world!";
std::wstring str2 = L"Hello"s + L", world!";
```
```cpp
std::string str = "my string";
bool contains = str.find("ring") != std::string::npos;
```
```cpp
const char* name1 = u8"John"; // 1 byte, UTF-8
const wchar_t* name2 = L"John"; // 2 (Win) 4 (Linux) bytes
const char16_t* name3 = u"John"; // 2 bytes, UTF-16
const char32_t* name4 = U"John"; // 4 bytes, UTF-32
```cpp
const char* str1 = "Line1\n"
"Line2\n"
"Line3\n";
Code of the if body will only execute if the condition value is anything other than
0.
Examples:
```cpp
int x = 5;
bool condition = x == 5;
if (condition)
x *= 2;
// - - -
const char* ptr = "Hello";
if (ptr) {
Log(ptr);
} else { // ptr == nullptr == 0
Log("Error!");
}
```
```cpp
int i = 0;
while (i < 5) {
Log("Hello!");
i++;
}
```
```cpp
for (int i = 0; i < 5; i++) {
Log("Hello!");
}
```
## _do-while_ loop
```cpp
bool correctNumber = false;
do {
Log("Select a number:");
int x = GetNumber();
if (x == 5) {
correctNumber = true;
}
} while (!correctNumber)
```
## _static_ keyword
Example:
```cpp
static double E = 2.71;
static void Foo() {}
```
```cpp
struct Entity {
static int idIncrement = 0;
int id;
Entity() {
id = idIncrement++;
}
```cpp
int Count() {
static int n = 1;
return n++;
}
```
## _extern_ keyword
```cpp
// main.cpp
extern int myVariable; // reference to myVariable in other.cpp
// - - -
// other.cpp
int myVariable = 5;
```
## _inline_ keyword
When a function with the _inline_ keyword is called, the linker will replace the
function call with the body of the function.
Example:
```cpp
#include <iostream>
int main() {
Log("Hi!");
}
```
## _sizeof_ keyword
```cpp
size_t charSize = sizeof char;
size_t intSize = sizeof(int);
```
## _const_ keyword
_const_ creates a constant that once assigned cannot be modified. It doesn't affect
at compiling.
```cpp
const double PI = 3.141592; // cannot change the value
```
Using _const_ before the pointer symbol won't allow to modify the contents of the
pointer, but it can be reassigned.
```cpp
const int* a = new int; // 'const int*' or 'int const*' are the same
*a = 2; // compile error
int b = 7;
a = &b; // this is fine
```
If instead it's after the pointer symbol, the pointer cannot be reassigned but its
contents can be modified.
```cpp
int* const a = new int;
*a = 2; // this if fine
a = nullptr; // compile error
```
A method with the _const_ cannot modify the class members (like a read-only
method).
```cpp
class Entity {
private:
int x_, y_;
int* id_;
public:
int GetX() const {
return x_;
}
void SetX(int x) {
x_ = x;
}
## _constexprt_ keyword
## _mutable_ keyword
A variable with the _mutable_ keyword can be modified from a _const_ method.
```cpp
class Entity {
private:
int x;
mutable int debug_count = 0;
public:
void GetX() const {
debug_count++;
return x;
}
}
```
A _mutable_ lambda can modify variables passed by value. At compiling, it's just
creating a new local variable.
```cpp
int x = 5;
// same behavior
auto g = [=]() {
int y = x;
y++;
// ...
}
```
The only difference between classes and structs is that by default, classes have
private visibilty and structs have public visibility.
```cpp
class Player {
private:
int x, y;
int speed;
public:
void Move(int xa, int ya) {
x += xa * speed;
y += ya * speed;
}
};
int main() {
Player player;
player.Move(1, -1);;
}
```
## _this_ keyword
```cpp
class Entity {
private:
int x, y;
public:
Entity(int x, int y) {
Entity* const e = this;
this->x = x;
this->y = y;
}
The arrow operator is a shortcut for accessing class members or methods on object
pointers.
```cpp
class Example {
public:
int a = 2;
void Print() {
// ...
}
}
```
```cpp
Example* e = new Example;
int x = e->a;
e->Print(); // (*e).Print();
```
## Visibility
- _private_ : can only be accessed from the class where it's declared.
- _protected_ : can only be accessed from the class and all it's subclasses.
- _public_ : can be accessed from everywhere.
## Instantiate Objects
Example object:
```cpp
class Example {
int a_;
public:
Example(int a) : a_(a) {}
}
```
```cpp
int a = 5;
int arr[10];
The _new_ keyword allocates memory on the heap, calls the constructor and returns a
pointer to where the object has been allocated.
Allocating on the heap takes longer, because the program has to find a big enough
part of contiguous memory to allocate the object. To free the used memory use the
_delete_ keyword. That will free the memory and call the destructor.
```cpp
int* a = new int;
*a = 5;
int* arr = new int[10];
Creating an object in an specific memory part. The provided pointer must have
allocated enough memory for the object to be placed.
```cpp
int* a = new int[50];
Example* e = new(a) Example();
```
## Implicit Conversion
```cpp
class Entity {
private:
std::string name_;
int age_;
public:
Entity(std::string name)
: name_(name), age_(-1) {}
Entity(int age)
: name_("Unknown"), age_(age) {}
}
```cpp
Entity e1 = "Example";
Entity e2 = 42;
PrintEntity(27);
// This doesn't work, because we are providing a 'const char*',
// not a 'std::string', and it would have to do
// two type conversions (from 'const* char' to 'std::string' and then to 'Entity&')
// PrintEntity("Name");
```
A constructor with the _explicit_ keyword won't allow to create an object using
implicit conversion.
```cpp
class Entity {
private:
std::string name_;
int age_;
public:
Entity(std::string name)
: name_(name), age_(-1) {}
explicit Entity(int age)
: name_("Unknown"), age_(age) {}
}
```
```cpp
Entity e1 = 22; // error
Entity e2(22); // ok
```
## Enums
Each enum value is just an integer. By default, the type is a 32 bit integer,
starting from 0.
```cpp
enum IpAddr {
V4, // 0
V6 // 1
};
int main() {
IpAddr ip1 = V4;
Example x = ExampleC;
}
```
## Constructor
```cpp
class Entity {
private:
int x_;
int y_;
public:
Entity(int x, int y) {
x_ = x;
y_ = y;
}
};
```
```cpp
class Entity {
Entity() = delete;
}
```
Member initializers should always be in the same order as they are declared in the
class, because that's the order they are initialized.
```cpp
class Entity {
private:
int x_;
int y_;
public:
Entity(int x, int y)
: x_(x), y_(y) {}
}
```
This is the more efficient way of initializing non-primitive members, because the
member is only assigned once and no default constructor is called.
```cpp
class Entity {
private:
std::string name; // default constructor called
public:
Entity() {
// equivalent to:
// name = std::string("Default");
name = "Default";
}
}
```
## Destructor
```cpp
class Entity {
~Entity() {}
}
```
## Copy Constructor
By default, C++ creates a copy constructor that copies the class members (a shallow
copy).
```cpp
Entity a = Entity();
Entity b = a; // creating a copy with the copy constructor
```
```cpp
class String {
String(const String& other) = delete;
}
```
## Inheritance
```cpp
class Base {};
class Derived : Base {};
```
## Virtual Functions
Using the _virtual_ keyword will generate a v-table for the function, so that if it
gets overriden the correct function is executed.
```cpp
class Base {
virtual void PrintName() {
std::cout << "Base" << std::endl;
}
};
class Derived {
void PrintName() override {
std::cout << "Derived" << std::endl;
}
}
int main() {
Base b = new Derived;
b.PrintName();
}
```
Subclasses of a superclass with a pure virtual function must implement the virtual
function to be able to instantiate the subclass.
```cpp
#include <string>
class Printable {
virtual std::string GetClassName() = 0;
}
## Ternary Operator
```cpp
int level = 5;
std::string rank = level > 7 ? "Master" : "Beginner";
```
## Operator Overloading
```cpp
#include <iostream>
struct Vector2 {
float x, y;
Vector2(float x, float y)
: x(x), y(y) {}
```cpp
Vector2 vec1(5.2, 3.4);
Vector2 vec2(7.1, 8.5);
Vector2 vec3(1.5, 6.4);
if (result1 == result2) {
std::cout << result1 << std::endl;
}
```
## Smart Pointers
```cpp
#include <memory>
class Example {
private:
int a;
public:
Example() : a(0) {}
Example(int a) : a(a) {}
void Print() {
// ...
}
}
```
### · *std::unique_ptr*
```cpp
std::unique_ptr<Example> var = std::make_unique<Example>();
var->Print();
```
### · *std::shared_ptr*
The object gets deleted when all the references to it get deleted. It works by
having a reference count and increasing it everytime the pointer gets copied.
```cpp
std::shared_ptr<Example> e;
{
std::shared_ptr<Example> var = std::make_shared<Example>();
e = var;
}
// 'e' is still valid
```
### · *std::weak_ptr*
```cpp
std::weak_ptr<Example> e;
{
std::shared_ptr<Example> var = std::make_shared<Example>();
e = var;
}
// e = nullptr;
```
## Dynamic Arrays
```cpp
#include <vector>
struct Vertex {
float x, y, z;
}
```cpp
std::vector<Vertex> vertices;
vertices.reserve(2); // reserve initial memory for 2 vertices
Vertex vert = { 1, 2, 3 };
vertices.push_back(vert); // copy a vertex to the array
vertices.emplace_back(4, 5, 6); // construct a Vertex with these parameters
## std::tuple, std::pair
```cpp
#include <tuple>
#include <string>
```cpp
auto sources = GetSources();
std::string src1 = std::get<0>(sources);
std::string src2 = std::get<1>(sources);
```
```cpp
auto sources = GetSources();
std::string src1 = sources.first;
std::string src2 = sources.second;
```
## Templates
```cpp
#include <iostream>
```cpp
Print<int>(5);
Print(5); // the type can be automatically deduced
## Useful Functions
- memset: set _count_ bytes of memory in the _dest_ pointer to the value _ch_.
```cpp
void* memset(void* dest, int ch, std::size_t count);
```
- malloc: allocate _size_ bytes of memory on the heap and return the pointer.
```cpp
void* malloc(size_t size);
```
```cpp
void free(void* ptr);
```
```cpp
struct Vector3 {
float x, y, z;
}
```
To get the offset of each member we are accessing the variables from an invalid
memory pointer (in this case, nullptr or 0), then we get the memory address of that
variable and finally we cast it into an _int_.
```cpp
int offset_x = (int) &((Vector3*) nullptr)->x; // 0
int offset_y = (int) &((Vector3*) nullptr)->y; // 4
int offset_z = (int) &((Vector3*) 0)->z; // 8
```
## Documentation