Template Classes and Functions:

b

Template Classes

b

Template Functions

b

Template Function and Type Inference

Passing Functions to Functions:

b

Function Pointers

b

Using Function Pointers

b

Object Slicing and Polymorphism

b

Abstract Classes and Pure Virtual Functions

b

Functors

C++ 11 Features:

b

Decltype, Typeid and Name Mangling

b

The Auto Keyword

b

Range-Based Loops

b

Nested Template Classes

b

Ring.h

b

A Ring Buffer Class

b

Ring.h

b

Making Classes Iterable

b

Ring.h

b

Initialization in C++ 98

b

Initialization in C++ 11

b

Initializer Lists

b

Object Initialization, Default and Delete

b

Introducing Lambda Expressions

b

Lambda Parameters and Return Types

b

Lambda Capture Expressions

b

Capturing this with Lambdas

b

The Standard Function Type

b

Mutable Lambdas

b

Delegating Constructors

b

Elision and Optimization

b

Constructors and Memory

b

Rvalues and Lvalues

b

Lvalue References

b

Rvalue References

b

Move Constructors

b

Move Assignment Operators

b

Static Casts

b

Dynamic Casts

b

Reinterpret Casts

b

Perfect Forwarding

b

Bind

b

Unique Pointers

b

Shared Pointers

Output:

Hello: 5
Hello again: 4

Template Classes:

#include <iostream>
#include <string>
using namespace std;
template<class T, class K>
class Test
{
private:
   T obj;
   K id;
public:
   Test(T obj, K m_id)
   {
      this->obj = obj;
      this->id = m_id;
   }
   void print()
   {
      cout << obj << “: ” << id << endl;
   }
};
int main()
{
   Test<string, int> test1(“Hello”, 5);
   test1.print();
   Test<string, double> test2(“Hello again”, 4.0);
   test2.print();
   return 0;
}

Output:

Hello
5
Hi there

Template Functions:

#include <iostream>
#include <string>

using namespace std;

template<class T>
void print(T n)
{
   cout << n << endl;
}

int main()
{
   print<string>(“Hello”);
   print<int>(5);

   print(“Hi there”);

   return 0;
}

Output:

Template version: Hello
Template version: 5
Template version: Hi there
Non-Template version: 5
Template version: 6
0

Template Functions and Type Inference:

#include <iostream>
#include <string>

using namespace std;

template<class T>
void print(T n)
{
   cout << “Template version: “<< n << endl;
}

void print(int value)
{
   cout << “Non-template version: ” << value << endl;
}

template<class T>
void show()
{
   cout << T() << endl;
}

int main()
{
   print<string>(“Hello”);
   print<int>(5);

   print(“Hi there”);

   print(5);
   print<>(6);

   show<double>();

   return 0;
}

Output:

Hello: 7
Hello: 8

Function Pointers:

#include <iostream>

using namespace std;

void test(int value)
{
   cout << “Hello: ” << value << endl;
}

int main()
{
   test(7);
   void (*pTest)(int) = test;
   pTest(8);

   return 0;
}

Output:

1
4
4

Using Function Pointers:

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

using namespace std;

bool match(string test)
{
   //return test == “two”;
   return test.size() == 3;
}

int countStrings(vector<string>& texts, bool (*functionPointer)(string))
{
   int tally = 0;

   for (int i = 0; i < texts.size(); i++)
   {
   if (match(texts[i]))
      tally++;
   }

   return tally;
}

int main()
{
   vector<string> texts;
   texts.push_back(“one”);
   texts.push_back(“two”);
   texts.push_back(“three”);
   texts.push_back(“two”);
   texts.push_back(“four”);
   texts.push_back(“two”);
   texts.push_back(“three”);

   cout << match(“one”) << endl;

   cout << count_if(texts.begin(), texts.end(), match) << endl; // calls match() on every value in texts

   cout << countStrings(texts, match) << endl; // passes (function pointer) match to function countStrings

   return 0;
}

Output:

child
copy parent
parent

Object Slicing and Polymorphism:

#include <iostream>

using namespace std;

class Parent
{
private:
   int one;

public:
   Parent() : one(0)
   {
   }

   Parent(const Parent& other) : one(0)
   {
      one = other.one;
      cout << “copy parent” << endl;
   }

   virtual void print()
   {
      cout << “parent” << endl;
   }

   virtual ~Parent()
   {
   }
};

class Child: public Parent
{
private:
   int two;

public:
   Child() : two(0)
   {
   }

   void print()
   {
      cout << “child” << endl;
   }
};

int main()
{
   Child c1;
   Parent& p1 = c1;
   p1.print(); // calls Child::print()

   Parent p2 = Child(); // calls Parent::Parent(const Parent& other) which slices off the Child::two parameter
   p2.print(); // calls Parent::print()

   return 0;
}

Output:

new labrador
Labrador running
Woof!
Woof!
new husky
Labrador running
Husky running

Abstract Classes and Pure Virtual Functions:

#include <iostream>

using namespace std;

class Animal
{
public:
   virtual void run() = 0;
   virtual void speak() = 0;
};

class Dog: public Animal
{
public:
   virtual void speak()
   {
      cout << “Woof!” << endl;
   }
};

class Labrador: public Dog
{
public:
   Labrador()
   {
      cout << “new labrador” << endl;
   }

   virtual void run()
   {
      cout << “Labrador running” << endl;
   }
};

class Husky: public Dog
{
public:
   Husky()
   {
      cout << “new husky” << endl;
   }

   virtual void run()
   {
      cout << “Husky running” << endl;
   }
};

void test(Animal& a)
{
   a.run();
}

int main()
{
   Labrador lab;
   lab.run();
   lab.speak();

   Animal* animals[5];
   animals[0] = &lab;
   animals[0]->speak();

   Husky husky;
   test(lab);

   test(husky);

   return 0;
}

Output:

1
Text matches!
No match.

Functors:

#include <iostream>

using namespace std;

struct Test
{
   virtual bool operator()(string& text) = 0;
};

struct MatchTest : Test
{
   virtual bool operator()(string& text)
   {
      return text == “lion”;
   }
};

struct MyMatchTest : Test
{
   virtual bool operator()(string& text)
   {
      return text == “text”;
   }
};

void check(string text, Test& t)
{
   if (t(text))
      cout << “Text matches!” << endl;
   else
      cout << “No match.” << endl;
}

int main()
{
   MatchTest pred;
   string value = “lion”;
   cout << pred(value) << endl; // calls MatchTest::operator()(“lion”) that returns 1
   check(value, pred); // calls if(t(text)) or if(pred(value)) or if(MatchTest(“lion”)) which returns true
   // so cout << “Text matches!” << endl;

   MyMatchTest myPred;
   check(value, myPred);

   return 0;
}

Output:

int
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
class Test
Bob

Decltype, Typeid and Name Mangling:

#include <iostream>
#include <string>
#include <typeinfo>

using namespace std;

class Test
{
public:
   Test() {}
   ~Test() {}
};

int main()
{
   int value;
   string str;
   Test test;

   cout << typeid(value).name() << endl;
   cout << typeid(str).name() << endl;
   cout << typeid(test).name() << endl;

   decltype(str) name = “Bob”;
   cout << name << endl;

   return 0;
}

Output:

11
999

The Auto Keyword:

#include <iostream>

using namespace std;

template<class T, class S>
auto test(T value1, S value2) -> decltype(value1 + value2)
{
   return value1 + value2;
}

int get()
{
   return 999;
}

auto test2() -> decltype(get())
{
   return get();
}

int main()
{
   auto value = 7;
   auto text = “Hello”;

   cout << test(5, 6) << endl;
   cout << test2() << endl;

   return 0;
}

Output:

one
two
three
5
7
9
11
H
e
l
l
o

Range-Based Loops:

#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
   auto texts = {“one”, “two”, “three”};
   for (auto text : texts)
      cout << text << endl;
   vector<int> numbers;
   numbers.push_back(5);
   numbers.push_back(7);
   numbers.push_back(9);
   numbers.push_back(11);
   for (auto number: numbers)
      cout << number << endl;
   string hello = “Hello”;
   for (auto c : hello)
      cout << c << endl;
   return 0;
}

Output:

Hello from iterator.
four
two
three

Nested Template Classes:

#include <iostream>
#include <string>
#include “ring.h”

using namespace std;

int main()
{
   ring<string>::iterator it;
   it.print();

   ring<string> textRing(3);
   textRing.add(“one”);
   textRing.add(“two”);
   textRing.add(“three”);
   textRing.add(“four”);

   for (auto i = 0; i < textRing.size(); i++)
      cout << textRing.get(i) << endl;

   return 0;
}

Output:

Ring.h:

#pragma once
#include <vector>
template <typename T>
class ring
{
   std::vector<T> _data;
   int _cur_index;
public:
   class iterator;
   ring(int size) : _cur_index(0)
   {
      _data.reserve(size);
      for (auto i = 0; i < size; i++)
         _data.push_back(T());
   }
   void add(T value)
   {
      if (_cur_index < _data.size())
      {
         _data[_cur_index] = value;
         _cur_index++;
      }
      else
      {
         _cur_index = 0;
         _data[_cur_index] = value;
      }
   }
   T get(int index)
   {
      if (index < _data.size())
         return _data[index];
      return T();
   }
   int size()
   {
      return static_cast<int>(_data.size());
   }
};
template<typename T>
class ring<T>::iterator
{
public:
   void print() const;
};
template<typename T>
void ring<T>::iterator::print() const
{
   std::cout << “Hello from iterator.” << std::endl;
}

Output:

four
two
three

A Ring Buffer Class:

#include <iostream>
#include <string>
#include “ring.h”

using namespace std;

int main()
{
   ring<string> textring(3);
   textring.add(“one”);
   textring.add(“two”);
   textring.add(“three”);
   textring.add(“four”);

   for (int i = 0; i < textring.size(); i++)
      cout << textring.get(i) << endl;

   return 0;
}

Output:

Ring.h:

#ifndef RING_H_
#define RING_H_

#include <iostream>

using namespace std;

template<class T>
class ring
{
private:
   int m_pos;
   int m_size;
   T* m_values;

public:
   class iterator;

   ring(int size) : m_pos(0), m_size(size), m_values(NULL)
   {
      m_values = new T[size];
   }

   ~ring()
   {
      delete [] m_values;
   }

   int size()
   {
      return m_size;
   }

   void add(T value)
   {
      m_values[m_pos++] = value;

      if (m_pos == m_size)
         m_pos = 0;
   }

   T& get(int pos)
   {
      return m_values[pos];
   }
};

template<class T>
class ring<T>::iterator
{
public:
   void print()
   {
      cout << “Hello from iterator: ” << T() << endl;
   }
};
#endif /* RING_H_ */

Output:

one
two
three

one
two
three

Making Classes Iterable:

#include <iostream>
#include <string>
#include “ring.h”

using namespace std;

int main()
{
   ring<string> textring(3);
   textring.add(“one”);
   textring.add(“two”);
   textring.add(“three”);

   // C++ 98 style
   for (ring<string>::iterator it = textring.begin(); it != textring.end(); it++)
      cout << *it << endl;

   cout << endl;

   // C++ 11 style
   for (auto val : textring)
      cout << val << endl;

   return 0;
}

Output:

Ring.h:

#ifndef RING_H_
#define RING_H_

#include <iostream>

using namespace std;

template<class T>
class ring
{
private:
   int m_pos;
   int m_size;
   T* m_values;

public:
   class iterator;

   ring(int size) : m_pos(0), m_size(size), m_values(nullptr)
   {
      m_values = new T[size];
   }

   ~ring()
   {
      delete[] m_values;
   }

   int size()
   {
      return m_size;
   }

   iterator begin()
   {
      return iterator(0, *this);
   }

   iterator end()
   {
      return iterator(m_size, *this);
   }

   void add(T value)
   {
      m_values[m_pos++] = value;

      if (m_pos == m_size)
         m_pos = 0;
   }

   T& get(int pos)
   {
      return m_values[pos];
   }
};

template<class T>
class ring<T>::iterator
{
private:
   int m_pos;
   ring& m_ring;

public:
   iterator(int pos, ring& ring_ref) : m_pos(pos), m_ring(ring_ref)
   {
   }

   //Post fix
   /*
   * This differs from what’s in at least the original
   * version of the tutorial video. Really we should
   * return a version of the iterator as it was
   * before it was modified, for consistency with
   * the usual behaviour of the postfix operator.
   */
   iterator operator++(int)
   {
      iterator old = *this;
      ++(*this);

      return old;
   }

   //prefix
   iterator& operator++()
   {
      ++m_pos;

      return *this;
   }

   T& operator*()
   {
      return m_ring.get(m_pos);
   }

   bool operator==(const iterator& other) const
   {
      return m_pos == other.m_pos;
   }

   bool operator!=(const iterator& other) const
   {
      return !(*this == other);
   }
};
#endif /* RING_H_ */

Output:

4
apple
orange
banana
one
two
three
four

Initialization in C++ 98:

#include <iostream>
#include <vector>
#include <string>
#include <initializer_list>

using namespace std;

class Test
{
public:
   Test(initializer_list<string> texts)
   {
      for (auto value : texts)
         cout << value << endl;
   }

   void print(initializer_list<string> strings)
   {
      for (auto value : strings)
         cout << value << endl;
   }
};

int main()
{
   vector<int> numbers{1, 3, 4, 6};
   cout << numbers[2] << endl;

   Test test{“apple”, “orange”, “banana”};
   test.print({ “one”, “two”, “three”, “four”});

   return 0;
}

Output:

2
0
00000000
0
Hi
three

Initialization in C++ 11:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
   int value{5};
   cout << value << endl;

   string text{“Hello”};
   cout << text << endl;

   int numbers[]{1, 2, 4};
   cout << numbers[1] << endl;

   int* pInts = new int[3]{1, 2, 3};
   cout << pInts[1] << endl;
   delete[] pInts;

   int value1{};
   cout << value1 << endl;

   int* pSomething{}; // equivalent to int *pSomething = nullptr;

   cout << pSomething << endl;

   int numbers1[5]{};
   cout << numbers1[1] << endl;

   struct
   {
      int value;
      string text;
   } s1{5, “Hi”};

   cout << s1.text << endl;

   vector<string> strings{“one”, “two”, “three”};
   cout << strings[2] << endl;

   return 0;
}

Output:

1
Hello
Hello
Hello
Hi

Initializer Lists:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
   int values[] = {1, 4, 5};
   cout << values[0] << endl;

   class C
   {
   public:
      string text;
      int id;
   };

   C c1 = {“Hello”, 7};
   cout << c1.text << endl;

   struct S
   {
      string text;
      int id;
   };

   S s1 = {“Hello”, 7};
   cout << s1.text << endl;

   struct
   {
      string text;
      int id;
   } r1 = {“Hello”, 7}, r2 = {“Hi”, 9};

   cout << r1.text << endl;
   cout << r2.text << endl;

   vector<string> strings;
   strings.push_back(“One”);
   strings.push_back(“Two”);
   strings.push_back(“Three”);

   return 0;
}

Output:

3: Mike
77: Mike

Object initialization, Default and Delete:

#include <iostream>
#include <string>
using namespace std;
class Test
{
   int id{3};
   string name{“Mike”};
public:
   Test() = default;
   Test(const Test& other) = delete;
   Test& operator=(const Test& other) = delete;
   Test(int id) : id(id)
   {
   }
   void print()
   {
      cout << id << “: ” << name << endl;
   }
};
int main()
{
   Test test;
   test.print();
   Test test1(77);
   test1.print();
   /**
   * Won’t work, we deleted them. 
   */
   //test2 = test;
   return 0;
}

Output:

Hello
Hello
Hello again

Introducing Lambda Expressions:

#include <iostream>
using namespace std;
void test(void (*pFunc)()) 
{
   pFunc();
}
int main()
{
   auto func = []() { cout << “Hello” << endl; };
   func();
   test(func);
   test([]() { cout << “Hello again” << endl; });
   return 0;
}

Output:

Hello Mike
Hello Bob
2
0
3

Lambda Parameters and Return Types:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

void testGreet(void (*greet)(string))
{
   greet(“Bob”);
}

void runDivide(double (*divide)(double a, double b))
{
   auto rval = divide(9, 3);
   cout << rval << endl;
}

int main()
{
   auto pGreet = [](string name) { cout << “Hello ” << name << endl;};
   pGreet(“Mike”);
   testGreet(pGreet);

   auto pDivide = [](double a, double b) -> double { if (b == 0.0) { return 0; } return a / b; };
   cout << pDivide(10.0, 5.0) << endl;
   cout << pDivide(10.0, 0.0) << endl;
   runDivide(pDivide);

   return 0;
}

Output:

1, 2
1, 2
1, 2
7
1, 8
8
100, 8
100

Lambda Capture Expressions:

#include <iostream>

using namespace std;

int main()
{
   int one = 1;
   int two = 2;
   int three = 3;

   // Capture one and two by value.
   [one, two]() { cout << one << “, ” << two << endl; }();

   // Capture all local variables by value.
   [=]() { cout << one << “, ” << two << endl; }();

   // Default capture all local variables by value, but three by reference.
   [=, &three]() { three = 7; cout << one << “, ” << two << endl; }();
   cout << three << endl;

   // Default capture all local variables by reference.
   [&]() { three = 7; two = 8; cout << one << “, ” << two << endl; }();
   cout << two << endl;

   // Default capture all local variables by reference but two and three by value.
   [&, two, three]() { one = 100; cout << one << “, ” << two << endl; }();
   cout << one << endl;

   return 0;
}

Output:

111
2
3
4

Capturing this with Lambdas:

#include <iostream>

using namespace std;

class Test
{
private:
   int one{1};
   int two{2};

public:
   void run()
   {
      int three{3};
      int four{4};

      auto pLambda = [&, this]()
      {
         one = 111;
         cout << one << endl;
         cout << two << endl;
         cout << three << endl;
         cout << four << endl;
      };

      pLambda();
   }
};

int main()
{
   Test test;
   test.run();

   return 0;
}

Output:

1
2
1
1
1
0
10

The Standard Function Type:

#include <iostream>
#include <functional>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

bool check(string& test)
{
   return test.size() == 3;
}

struct Check
{
   bool operator()(string& test)
   {
      return test.size() == 5;
   }
} check1;

void run(function<bool(string&)> check)
{
   string test = “stars”;
   cout << check(test) << endl;
}

int main()
{
   int size = 5;
   auto lambda = [size](string test){ return test.size() == size; };

   vector<string> vec{“one”, “two”, “three”};
   auto count = count_if(vec.begin(), vec.end(), lambda);
   cout << count << endl;

   count = count_if(vec.begin(), vec.end(), check);
   cout << count << endl;

   count = count_if(vec.begin(), vec.end(), check1);
   cout << count << endl;

   run(lambda);
   run(check1);
   run(check);

   function<int(int, int)> add = [](int one, int two){ return one + two; };
   cout << add(7, 3) << endl;

   return 0;
}

Output:

8
5

Mutable Lambdas:

#include <iostream>

using namespace std;

int main()
{
   int cats = 5;

   [cats]() mutable { cats = 8; cout << cats << endl; }();
   cout << cats << endl;

   return 0;
}

Output:

string parent constructor
string parent constructor
No parameter parent constructor

Delegating Constructors:

#include <iostream>
using namespace std;
class Parent
{
   int dogs{5};
   string text{“hello”};
public:
   Parent() : Parent(“hello”)
   {
      cout << “No parameter parent constructor” << endl;
   }
   Parent(string text)
   {
      cout << “string parent constructor” << endl;
   }
};
class Child : public Parent
{
public:
   Child() = default;
};
int main()
{
   Parent parent(“Hello”);
   Child child;
   return 0;
}

Output:

constructor
Hello from test
constructor
copy constructor
destructor

Elision and Optimization:

#include <iostream>
#include <vector>

using namespace std;

class Test
{
public:
   Test()
   {
      cout << “constructor” << endl;
   }

   Test(int i)
   {
      cout << “parameterized constructor” << endl;
   }

   Test(const Test& other)
   {
      cout << “copy constructor” << endl;
   }

   Test& operator=(const Test& other)
   {
      cout << “assignment” << endl;
      return *this;
   }

   ~Test()
   {
      cout << “destructor” << endl;
   }

   friend ostream &operator<<(ostream& out, const Test& test);
};

ostream& operator<<(ostream& out, const Test& test)
{
   out << “Hello from test”;
   return out;
}

Test getTest()
{
   return Test();
}

int main()
{
   Test test1 = getTest();
   cout << test1 << endl;

   vector<Test> vec;
   vec.push_back(Test());

   return 0;
}

Output:

constructor
Hello from test
constructor
copy constructor
destructor

Constructors and Memory:

#include <iostream>
#include <vector>
#include <memory.h>

using namespace std;

class Test
{
private:
   static const int SIZE = 100;
   int* _pBuffer;

public:
   Test()
   {
      cout << “constructor” << endl;
      _pBuffer = new int[SIZE] {};
   }

   Test(int i)
   {
      cout << “parameterized constructor” << endl;
      _pBuffer = new int[SIZE] {};

      for (int i = 0; i < SIZE; i++)
         _pBuffer[i] = 7 * i;
   }

Test(const Test& other)
{
   cout << “copy constructor” << endl;
   _pBuffer = new int[SIZE] {};

   // alternate way to copy buffer.
   //std::copy(other._pBuffer, other._pBuffer + SIZE, _pBuffer);

   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));
}

Test& operator=(const Test& other)
{
   cout << “assignment” << endl;
   _pBuffer = new int[SIZE] { };

   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));
   return *this;
}

~Test()
{
   cout << “destructor” << endl;
   delete[] _pBuffer;
}

   friend ostream &operator<<(ostream& out, const Test& test);
};

ostream& operator<<(ostream& out, const Test& test)
{
   out << “Hello from test”;
   return out;
}

Test getTest()
{
   return Test();
}

int main()
{
   Test test1 = getTest();
   cout << test1 << endl;

   vector<Test> vec;
   vec.push_back(Test());

   return 0;
}

Output:

constructor
Hello from test
constructor
copy constructor
destructor
8

Rvalues and Lvalues:

#include <iostream>
#include <vector>
#include <memory.h>

using namespace std;

class Test
{
private:
   static const int SIZE = 100;
   int* _pBuffer;

public:
   Test()
   {
      cout << “constructor” << endl;

      _pBuffer = new int[SIZE] {};
   }

Test(int i)
{
   cout << “parameterized constructor” << endl;

   _pBuffer = new int[SIZE] {};

   for (int i = 0; i < SIZE; i++)
      _pBuffer[i] = 7 * i;
}

Test(const Test& other)
{
   cout << “copy constructor” << endl;

   _pBuffer = new int[SIZE] {};
   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));
}

Test& operator=(const Test& other)
{
   cout << “assignment” << endl;

   _pBuffer = new int[SIZE] {};
   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));

   return *this;
}

~Test()
{
   cout << “destructor” << endl;

   delete[] _pBuffer;
}

   friend ostream &operator<<(ostream &out, const Test &test);
};

ostream& operator<<(ostream& out, const Test& test)
{
   out << “Hello from test”;

   return out;
}

Test getTest()
{
   return Test();
}

int main()
{
   Test test1 = getTest();
   cout << test1 << endl;

   vector<Test> vec;
   vec.push_back(Test());

   int value1 = 7;
   int* pValue1 = &value1;
   //int* pValue2 = &7;

   Test* pTest1 = &test1;
   //Test* pTest2 = &getTest();

   int* pValue3 = &++value1;
   cout << *pValue3 << endl;

   //int *pValue4 = &value1++;

   //int *s = &(7 + value1);

   return 0;
}

Output:

Hello from test
constructor
copy constructor
destructor
constructor
parameterized constructor

Lvalue References:

#include <iostream>
#include <vector>
#include <memory.h>

using namespace std;

class Test
{
private:
   static const int SIZE = 100;
   int* _pBuffer;

public:
   Test()
   {
      cout << “constructor” << endl;

      _pBuffer = new int[SIZE] {};
}

Test(int i)
{
   cout << “parameterized constructor” << endl;

   _pBuffer = new int[SIZE] {};

   for (int i = 0; i < SIZE; i++)
      _pBuffer[i] = 7 * i;
}

Test(const Test& other)
{
   cout << “copy constructor” << endl;

   _pBuffer = new int[SIZE] {};
   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));
}

Test& operator=(const Test& other)
{
   cout << “assignment” << endl;

   _pBuffer = new int[SIZE] {};
   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));

   return *this;
}

~Test()
{
   cout << “destructor” << endl;

   delete[] _pBuffer;
}

   friend ostream &operator<<(ostream &out, const Test &test);
};

ostream& operator<<(ostream& out, const Test& test)
{
   out << “Hello from test”;
   return out;
}

Test getTest()
{
   return Test();
}

int main()
{
   Test test1 = getTest();
   cout << test1 << endl;

   vector<Test> vec;
   vec.push_back(Test());

   Test& rTest1 = test1;
   //Test& rTest2 = getTest();
   const Test& rTest2 = getTest();
   Test test2(Test(1));

   return 0;
}

Output:

constructor
copy constructor
destructor
constructor
lValue function!
constructor
rValue function!
destructor
constructor
rValue function!
destructor
lValue int func!
rValue int func!

Rvalue References:

#include <iostream>
#include <vector>
#include <memory.h>

using namespace std;

class Test
{
private:
   static const int SIZE = 100;
   int* _pBuffer;

public:
   Test()
   {
   cout << “constructor” << endl;

   _pBuffer = new int[SIZE] {};
   }

Test(int i)
{
   cout << “parameterized constructor” << endl;

   _pBuffer = new int[SIZE] {};

   for (int i = 0; i < SIZE; i++)
      _pBuffer[i] = 7 * i;
}

Test(const Test& other)
{
   cout << “copy constructor” << endl;

   _pBuffer = new int[SIZE] {};
   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));
}

Test& operator=(const Test& other)
{
   cout << “assignment” << endl;

   _pBuffer = new int[SIZE] {};
   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));

   return *this;
}

~Test()
{
   cout << “destructor” << endl;

   delete[] _pBuffer;
}

   friend ostream& operator<<(ostream& out, const Test& test);
};

ostream& operator<<(ostream& out, const Test& test)
{
   out << “Hello from test”;

   return out;
}

Test getTest()
{
   return Test();
}

void check(const Test &value)
{
   cout << “lValue function!” << endl;
}

void check(Test&& value)
{
   cout << “rValue function!” << endl;
}

void intTest(const int& value)
{
   cout << “lValue int func!” << endl;
}

void intTest(int &&value)
{
   cout << “rValue int func!” << endl;
}

int main()
{
   Test test1 = getTest();
   cout << test1 << endl;

   vector<Test> vec;
   vec.push_back(Test());

   Test& ltest1 = test1;

   Test&& rtest1 = getTest();

   check(test1);
   check(getTest());
   check(Test());

   int num = 4;
   intTest(++num);
   intTest(num++);

   return 0;
}

Output:

Move constructor

Move Constructors:

#include <iostream>
#include <vector>
#include <memory.h>

using namespace std;

class Test
{
private:
   static const int SIZE = 100;
   int* _pBuffer{nullptr};

public:
   Test()
   {
      _pBuffer = new int[SIZE] {};
   }

Test(int i)
{
   _pBuffer = new int[SIZE] {};

   for (int i = 0; i < SIZE; i++)
      _pBuffer[i] = 7 * i;
}

Test(const Test& other)
{
   _pBuffer = new int[SIZE] {};
   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));
}

Test(Test&& other)
{
   cout << “Move constructor” << endl;

   _pBuffer = other._pBuffer;
   other._pBuffer = nullptr;
}

Test& operator=(const Test& other)
{
   _pBuffer = new int[SIZE] {};
   memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));

   return *this;
}

~Test()
{
   delete[] _pBuffer;
}

   friend ostream& operator<<(ostream& out, const Test& test);
};

ostream& operator<<(ostream& out, const Test& test)
{
   out << “Hello from test”;

   return out;
}

Test getTest()
{
   return Test();
}

int main()
{
   vector<Test> vec;
   vec.push_back(Test());

return 0;
}

Output:

Move constructor
Move assignment

Move Assignment Operators:

#include <iostream>
#include <vector>
#include <memory.h>

using namespace std;

class Test
{
private:
   static const int SIZE = 100;
   int* _pBuffer{nullptr};

public:
   Test()
   {
      _pBuffer = new int[SIZE] {};
   }

   Test(int i)
   {
      _pBuffer = new int[SIZE] {};

      for (int i = 0; i < SIZE; i++)
      _pBuffer[i] = 7 * i;
   }

   Test(const Test& other)
   {
      _pBuffer = new int[SIZE] {};
      memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));
   }

   Test(Test&& other)
   {
      cout << “Move constructor” << endl;

      _pBuffer = other._pBuffer;
      other._pBuffer = nullptr;
   }

   Test& operator=(const Test& other)
   {
      _pBuffer = new int[SIZE] {};
      memcpy(_pBuffer, other._pBuffer, SIZE * sizeof(int));

      return *this;
   }

   Test& operator=(Test&& other)
   {
      cout << “Move assignment” << endl;

      delete [] _pBuffer;
      _pBuffer = other._pBuffer;
      other._pBuffer = nullptr;

      return *this;
   }

   ~Test()
   {
      delete[] _pBuffer;
   }

   friend ostream &operator<<(ostream& out, const Test& test);
};

ostream& operator<<(ostream& out, const Test& test)
{
   out << “Hello from test”;

   return out;
}

Test getTest()
{
   return Test();
}

int main()
{
   vector<Test> vec;
   vec.push_back(Test());

   Test test;
   test = getTest();

   return 0;
}

Output:

00DAF817
parent!

Static Casts:

#include <iostream>

using namespace std;

class Parent
{
public:
   void speak()
   {
      cout << “parent!” << endl;
   }
};

class Brother: public Parent
{
};

class Sister: public Parent
{
};

int main()
{
   Parent parent;
   Brother brother;

   Parent* ppb = &brother;
   Brother* pbb = static_cast<Brother*>(ppb);
   cout << pbb << endl;

   Parent&& p = static_cast<Parent&&>(parent);
   p.speak();

   return 0;
}

Output:

00D3FCA8

Dynamic Casts:

#include <iostream>

using namespace std;

class Parent
{
public:
   virtual void speak()
   {
      cout << “parent!” << endl;
   }
};

class Brother : public Parent
{
};

class Sister : public Parent
{
};

int main()
{
   Parent parent;
   Brother brother;

   Parent* ppb = &brother;
   Brother* pbb = dynamic_cast<Brother*>(ppb);

   if (pbb == nullptr)
      cout << “Invalid cast” << endl;
   else
      cout << pbb << endl;

   return 0;
}

Output:

005DFDD8

Reinterpret Casts:

#include <iostream>

using namespace std;

class Parent
{
public:
   virtual void speak()
   {
      cout << “parent!” << endl;
   }
};

class Brother: public Parent
{
};

class Sister: public Parent
{
};

int main()
{
   Parent parent;
   Brother brother;
   Sister sister;

   Parent* ppb = &brother;
   Sister* pbb = reinterpret_cast<Sister*>(ppb);

   if (pbb == nullptr)
      cout << “Invalid cast” << endl;
   else
      cout << pbb << endl;

   return 0;
}

Output:

lvalue

Perfect Forwarding:

#include <iostream>

using namespace std;

class Test
{
};

template<typename T>
void call(T&& arg)
{
   check(forward<T>(arg));
}

void check(Test& test)
{
   cout << “lvalue” << endl;
}

void check(Test&& test)
{
   cout << “rvalue” << endl;
}

int main()
{
   Test test;
   call(test);

   return 0;
}

Output:

3, 100, 7
110

5
5
0.2
3
20
10

Bind:

#include <iostream>
#include <functional>

using namespace std;
using namespace placeholders;

class Test
{
public:
   int add(int a, int b, int c)
   {
      cout << a << “, ” << b << “, ” << c << endl;
      return a + b + c;
   }
};

int run(function<int(int, int)> func)
{
   return func(7, 3);
}

double my_divide (double x, double y)
{
   return x / y;
}

struct MyPair
{
   double a, b;

   double multiply()
   {
      return a * b;
   }
};

int main()
{
   Test test;
   auto calculate = bind(&Test::add, test, _2, 100, _1); // returns test.add(_2, 100, _1)
   cout << run(calculate) << endl; // calls run(test.add(3, 100, 7))

   // binding functions:
   auto fn_five = std::bind(my_divide, 10, 2); // returns 10 / 2
   std::cout << fn_five() << ‘\n’; // 5

   auto fn_half = std::bind(my_divide, _1, 2); // returns x / 2
   std::cout << fn_half(10) << ‘\n’; // 5

   auto fn_invert = std::bind(my_divide, _2, _1); // returns y / x
   std::cout << fn_invert(10, 2) << ‘\n’; // 0.2

   auto fn_rounding = std::bind<int>(my_divide,_1, _2); // returns int(x / y)
   std::cout << fn_rounding(10, 3) << ‘\n’; // 3

   MyPair ten_two { 10, 2 };

   // binding members:
   auto bound_member_fn = std::bind(&MyPair::multiply, _1); // returns x.multiply()
   std::cout << bound_member_fn(ten_two) << ‘\n’; // 20

   auto bound_member_data = std::bind(&MyPair::a, ten_two); // returns ten_two.a
   std::cout << bound_member_data() << ‘\n’; // 10

   return 0;
}

Output:

created
created
created
created
Hello
Finished

Unique Pointers:

#include <iostream>
#include <memory>

using namespace std;

class Test
{
public:
   Test()
   {
      cout << “created” << endl;
   }

   void greet()
   {
      cout << “Hello” << endl;
   }

   ~Test()
   {
      cout << “destroyed” << endl;
   }
};

class Temp
{
private:
   unique_ptr<Test[]> pTest;

public:
   Temp() : pTest(new Test[2])
   {
   }
};

int main()
{
   Temp temp;

   unique_ptr<Test[]> pTest(new Test[2]);
   pTest[1].greet();

   cout << “Finished” << endl;

   return 0;
}

Output:

created
Finished

Shared Pointers:

#include <iostream>
#include <memory>
using namespace std;
class Test
{
public:
   Test()
   {
      cout << “created” << endl;
   }
   void greet()
   {
      cout << “Hello” << endl;
   }
   ~Test()
   {
      cout << “destroyed” << endl;
   }
};
int main()
{
   shared_ptr<Test> pTest2(nullptr);
   {
      shared_ptr<Test> pTest1 = make_shared<Test>();
      pTest2 = pTest1;
      auto pTest3 = pTest1;
   }
   cout << “Finished” << endl;
   return 0;
}