Template Classes and Functions:
Template Classes
Template Functions
Template Function and Type Inference
Passing Functions to Functions:
Function Pointers
Using Function Pointers
Object Slicing and Polymorphism
Abstract Classes and Pure Virtual Functions
Functors
C++ 11 Features:
Decltype, Typeid and Name Mangling
The Auto Keyword
Range-Based Loops
Nested Template Classes
Ring.h
A Ring Buffer Class
Ring.h
Making Classes Iterable
Ring.h
Initialization in C++ 98
Initialization in C++ 11
Initializer Lists
Object Initialization, Default and Delete
Introducing Lambda Expressions
Lambda Parameters and Return Types
Lambda Capture Expressions
Capturing this with Lambdas
The Standard Function Type
Mutable Lambdas
Delegating Constructors
Elision and Optimization
Constructors and Memory
Rvalues and Lvalues
Lvalue References
Rvalue References
Move Constructors
Move Assignment Operators
Static Casts
Dynamic Casts
Reinterpret Casts
Perfect Forwarding
Bind
Unique Pointers
Shared Pointers
Output:
Hello: 5
Hello again: 4
Template Classes:
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:
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:
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:
Output:
Hello
Hello
Hello again
Introducing Lambda Expressions:
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:
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: