If you find the information in this page useful and want to show your support, you can make a donation
Use PayPal
This will help me create more stuff and fix the existent content...
sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt update sudo apt install gcc-11 g++-11 gcc-11 --version
// g++-11 main.cpp -o main && ./main
#include <iostream>
int main() {
std::cout << "Hello World C++!\n";
}
PNAME="p1testcpp"; cd .; mkdir -p $PNAME/src;
printf '#include <iostream>\nusing namespace std;\n\nint main(){\ncout << "Hello Template" << endl;\nreturn 0;\n}\n' > $PNAME/src/main.cpp
g++ -Wall -std=c++14 main.cpp -o main && ./main
TARGET=main.out
SRCS:=main.cpp
CC = g++-11
CFLAGS = -Wall -Werror
OBJS = $(SRCS:.cpp=.o)
%.o : %.cpp
$(CC) -c $< $(CFLAGS) -o $@
.PHONY: all
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $(TARGET) $(OBJS)
.PHONY: clean
clean:
rm -rf $(OBJS) $(TARGET)
.PHONY: test
test: clean all
./$(TARGET)
C++ is a general purpose programming language with a bias towards systems programming which supports the following coding paradigms:
C++ is used to write code at all levels, including firmware, operating systems, and large-scale applications.
char type is used to represent the numeric values for character data as represented by the basic character set present on a particular computer. This is determined by the locale settings.wchar_t type is used which expands on the numeric values available to represent character sets from various languages found around the world (E.g a character data that doesn't fit in the standard ASCII character set, such as Japanese kanji)
#include <climits> library for size and precision when declaring primitive data typesenum Month { January = 1, February, March, April, May, June, July, August, September, October, November, December };
const & constexprstd::string class data pointer and n for the number of lements (size() returns n)std:string objects can be used like local variables std::string h{"Hello"};std::vector classstd::string but can store data of any typesize() returns number of elements and push_back() add element at the end{} and parenthesis ()
#include <iostream>
#include <climits>
#include <vector>
//typedef std::vector<int> IntVec; // alias old C and C++
using IntVec = std::vector<int>;// Modern C++
class MyClass {};
int main() {
int myVar = 0;
int yourVar{1};
bool flag{ true };
int zeroVar{};
double myDouble(53.53);
vector<int> vec{1,2,3,4,5,6};
int intArray[] {1,2,4,6};
string s{"My String"}; // sames as: string s("My String");
std::vector<int> old_one(4); // std::vector variable with elements 0, 0, 0, 0
std::vector<int> old_two(4, 2); // std::vector variable with elements 2, 2, 2, 2
std::vector<int> uni_one{4}; // std::vector variable with elements 4
std::vector<int> uni_two{4, 2}; // std::vector variable with elements 4, 2
std::vector<IntVec> vec_of_vec;
MyClass mc{}; // removes ambiguity, it doesnt look like a func declaration
bool a = true;
char b = 'b';
signed char c = -1;
signed char d = 64;
short e = -16384;
unsigned short f = 16384;
int g = -2;
unsigned int h = 32768;
long int i = -32768;
long unsigned int j = -32768;
long long int k = -4294967296;
long long unsigned int l = 4294967296;
float m = 3.141615;
double n = 3.141615;
const char *str = "Hello"; // Equivalent to const char str[] = {'H','e','l','l','o','\0'}
std::cout << "bool " << a << " sizeof " << sizeof(a) << "\n";
std::cout << "char " << b << " sizeof " << sizeof(b) << "\n";
std::cout << "signed char " << c << " sizeof " << sizeof(c) << "\n";
std::cout << "signed char " << d << " sizeof " << sizeof(d) << "\n";
std::cout << "short " << e << " sizeof " << sizeof(e) << "\n";
std::cout << "unsigned short " << f << " sizeof " << sizeof(f) << "\n";
std::cout << "int " << g << " sizeof " << sizeof(g) << "\n";
std::cout << "unsigned int " << h << " sizeof " << sizeof(h) << "\n";
std::cout << "long int " << i << " sizeof " << sizeof(i) << "\n";
std::cout << "long unsigned int " << j << " sizeof " << sizeof(j) << "\n";
std::cout << "long long int " << k << " sizeof " << sizeof(k) << "\n";
std::cout << "long long unsigned int " << l << "sizeof " << sizeof(l) << "\n";
std::cout << "float " << m << " sizeof " << sizeof(m) << "\n";
std::cout << "double " << n << " sizeof " << sizeof(n) << "\n";
//std::cout << "Square auto func " << square(g) << "\n";
std::cout << "char MIN " << CHAR_MIN << "\n";
std::cout << "int MIN " << INT_MIN << "\n";
std::cout << "short MIN " << SHRT_MIN << "\n";
std::cout << "long MIN " << LONG_MIN << "\n";
std::cout << "long long MIN " << LLONG_MIN << "\n";
std::cout << "char MAX " << CHAR_MAX << "\n";
std::cout << "int MAX " << INT_MAX << "\n";
std::cout << "short MAX " << SHRT_MAX << "\n";
std::cout << "long MAX " << LONG_MAX << "\n";
std::cout << "long long MAX " << LLONG_MAX << "\n";
// The comma operator has left-to-right associativity. It evaluates the left expression,
// discards its result, and returns the right expression
int x = (g++, 6);
std::cout << "Comma operator test x=" << x << " g=" << g << "\n";
/*
Comma operator test x=6 g=-1
*/
// C++20 three-way comparison operator <=> a.k.a. 'spaceship operator'
// operator compares alphabetical order like strcmp
// operator returns an object that can be directly compared with a positive, 0, or negative integer value
std::cout << "Spaceship operator test " << ((3 <=> 5) == 0) << "\n";
std::cout << "Spaceship operator test " << ((3 <=> 5) < 0) << "\n";
std::cout << "Spaceship operator test " << ((3 <=> 5) > 0) << "\n";
/*
Spaceship operator test 0
Spaceship operator test 1
Spaceship operator test 0
*/
// C++20 introduces a set of safe compare functions <utility>
// bool cmp_equal(T1 a, T2 b)
// bool cmp_not_equal(T1 a, T2 b)
// bool cmp_less(T1 a, T2 b)
// bool cmp_greater(T1 a, T2 b)
// bool cmp_less_equal(T1 a, T2 b)
// bool cmp_greater_equal(T1 a, T2 b)
unsigned o = 4;
int p = -3;
std::cout << "Without utility " << (o > p) << " With utility " << std::cmp_greater(o,p) << "\n";
/* Without utility 0 With utility 1 */
}if (auto iter = begin(vec) ; iter != end(vec)) varible is local to if-else statementswitch (char c = arr[i]; c)
f and UL to change thisconst char *cca="Hello" is null terminated array of const char which has limited functionality, for pure C++ string objects are recommendedR and () if string has () needs an extra delimiter. Examples:std::string url = R"(<a href="file">C:\Program Files\</a>\n)";std::string delimited_with_x_url = R"x(<a href="file">C:\"Program Files (x86)"\</a>\n)x";A namespace is a "scope container" where you can place your classes, variables, or other identifiers to prevent conflicts with others.
Anytime you want to reduce ambiguity or name collisions, you use the namespace designator ahead of the identifier.
E.g. using namespace MyNameSpace (Avoid using the this using namesoace in headers as it will then be included whenever the header is included and will highly likely result in name clashes)
The :: is the scope resolution operator and allows you gain access to classes, variables, or other identifiers in the std namespace. E.g. std::cout means the cout object exists in the namespace std
You can define your own namespace by using the keyword namespace and nested namespaces if you choose to provide more separation of identifiers in your code. Namespaces can be combined to form new namespaces as well
namespace MyNameSpace {
namespace Geometry {
const double PI = 3.14159;
double Area(double r) {
return PI*(r*r);
}
}
}
//Combined namespace
namespace MyNameSpace_std {
using namespace MyNameSpace;
using namespace std;
}
using namespace MyNameSpace;
int main() {
double radius = 12.5;
double area = Geometry::Area(radius);
}
| Expression | Description | Example |
|---|---|---|
*p++ *(p++) |
Extracts value pointed by p then p is incremented |
*p++ = 1; is equivalent to *p = 1; p++; |
(*p)++ |
The value that p points to is incremented |
(*p)++; is equivalent to *p = *p + 1; |
*++p *(++p) |
First increment p then the new address that p points to now (after the increment) is extracted |
*++p = 1; is equivalent to p++; *p = 1; |
++*p ++(*p) |
Increments the value pointed by p then extract the value pointed by p (evaluates *p) |
++*p = 1; is equivalent to (*p)++; *p = 1; |
sizeof on a class will return the sum of all the members/attributes (the size of the methods is omitted for this calculation)struct in C++ is the same as class, except all the members are public by defaultWhen you call a member function (of an object), the object is passed by address in a hidden argument called this which you can deferecne to access the members of the object
class Test {
int i;
std::string s;
public:
func(int a, float b, std::string s);
};
void Test::fun(int a, float b, std::string s) {
this->i = 1; // 'this' is equal to &test (the address of test)
}
Test test;
test.func(1, 2.0, "Three"); // Is called as Test::func(&test, 1, 2.0,"Three");
Attributes in an object can also be initialized using the brackets initializer
{}, empty braces will call the default constructor, if defined. E.g.class Rectangle { public: int w; int h; }; Rectangle myRec{10, 7}; Rectangle otherRec{};Constructor of astaticobject is called only once when the program execution reaches for the first time the place where the object is defined
A Copy Constructor is used to make a copy of an existing object instance. If you do not declare a copy constructor the compiler will generate one for you automatically.
The compiler generated one is only capable of a shallow member copy, If you have pointers to memory locations in your class you will need to create a copy constructor to copy the data pointed by these pointers correctly/explicitly
There are 4 possible function signatures for a copy constructor.
MyClass(const MyClass& other); This is the most common to avoid changing something on the object you are copyingMyClass(MyClass& other);MyClass(volatile const MyClass& other);MyClass(volatile MyClass& other); class Test {
int i;
std::string s;
public:
func(int a, float b, std::string s);
};
Test(const Test& other) : i(other.i), str(other.str) {
}
= with objects)= is used in the initialization of an object, implicitly the compiler will use the copy constructor in case the equals operator (=) is not overloaded= to assign object we must overload the operator accordingly or explicitly implement the copy constructor with our code.= operator).hpp: MyClass& operator =(const MyClass &rhs); .cpp: MyClass& MyClass::operator =(const MyClass &rhs)class Test {
int i;
std::string s;
public:
func(int a, float b, std::string s);
};
Test& operator=(const Test& other_on_the_right_side) {
i = other.i;
str = other.str;
return *this;
}
// file: person.hpp
#include <iostream>
class Person {
public:
Person(std::string name, unsigned int age); // constructor
void print_person_info(void);
~Person(); // destructor
private:
std::string name;
unsigned int age;
};
// file: person.cpp
#include "person.hpp"
Person::Person(std::string name, unsigned int age) {
this->name = name;
this->age = age;
}
void Person::print_person_info(void) {
std::cout << "Person name: " << this->name << " age: " << this->age << std::endl;
}
Person::~Person() {
std::cout << this->name << " Person Object Destructor" << std::endl;
}
They are like pointers because they actually modify the memory of the variable/object they are referring
It can be thought as an alias, that is, another name for an already existing variable.
When a variable is declared as reference, it becomes an alternative name for an existing variable
They are like constant pointer that is automatically dereferenced when you use it
Mostly used for
A variable can be declared as reference by putting & in the declaration
Differences with pointers:
void but a reference can never be voidNULL. A reference must be initialized to a variable when declaredPass by const reference
// file: main.cpp
// g++ -std=c++11 -Wall ./main.cpp -o test
#include <iostream>
#include <memory>
// Using Pointers
void swap_ptr(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// Using C++ References
// when called references 'a' and 'b' are created and refer to the variables passed as parameter
// so 'a' and 'b can modify those variables which are defined outside the scope of this function
void swap_ref(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main(int argc, char *argv[]) {
int x = 7, y = 17;
swap_ref(x, y); // with references
swap_ptr(&x, &y); // with pointers
vector<string> names {"anna", "ben", "camila"};
for (auto const &str:names)
cout << str << "\n"; // no change
for (auto &str:names)
str = "noname"; // change
}
const Objectsconst objects CAN'T make a call to their methods unless these are defined as const as well (E.g. int get_area () const { return w*h; }const functions defined inside a const object cannot modify the object eitherget functions as constconstconst functions can be overloaded with non-const functions and the one called will depend of the object that is calling it,
if the object is const the const function version will be called if not the non-const version will be called insteadconst pointers table| Declaration | Case | Description |
|---|---|---|
int* ptr |
No const pointer and No const data |
The pointer can be modified to point to other data and the data that it points to can be modified |
const int* ptr |
No const pointer and const data |
The pointer can be modified to point to other data but the data that it points to CAN'T be modified using the pointer |
int* const ptr = &x |
const pointer and No const data |
The pointer can only point to the value it was initialized, we CAN'T change it to point to different data but we can modify the data using the pointer |
const int* const ptr = &x |
const pointer and const data |
The pointer can only point to the value it was initialized and the data that it points to CAN'T be modified using the pointer either |
void display(const vector<string> *const v) {
// (*v).at(0) = "Name"; //const to prevent this
for (auto e: *v) {
cout << e << "";
cout << endl;
}
//v = nullptr; //*const to prevent this
}
: operator in constructors)const members
// file: student.cpp
...
// Base class constructor (Person in this case) must be called from the initialization list
// RACE is a const member
Student::Student(std::string name, unsigned int age, std::string school) : Person(name, age), RACE("human") {
this->school = school;
}
...
:A class can define an external function as a friend function. This allows the friend function to access all the members of the class (public and private) but these functions
are non-members, which means they don't receive a this pointer. Consequently, they must require an explicit parameter to access an object.
Friend functions are declared in the class definition (usually .hpp) with friend and then implemented in the .cpp but without the ClassName:: syntax (because they are not members of the class)
The implementation of friend functions can be in any other place it's desired, if they are implemented in the class that does NOT make them methods of the class
this pointerthis, so we can use it to access the object attributes and methodsthis as argument (except to the static methods)new & deleteThe new operator is used to dynamically allocate memory and when used does the following:
The delete operator is used to free/release allocated memory and when used does the following:
dangling pointer The pointer variable that points to the released memory will still exist on the stack until the end of it's scopeExample:
Time* timePtr = new Time(1, 1, 1);
delete timePtr;
int* array = new int[10];
delete [] array; // to delete dynamically allocated array through a pointer we must use [] to delete all elements
int *p1 = new int{36};
int *p2 = new int(37);
The OS restricts the amount of memory a program may allocate if try to locate over this resctriction most likely will get a
nullptr(git a Memory exhaustion failur)
static class attributes & methods:: operatorstatic can ONLY access static attributes, this means it can NOT access non-static attributesstatic method does NOT have a this pointer because this pointer must refer to a specific object of the classstatic functions cannot be const (TODO: need to check reason for this).hpp and initialized in the .cpp using the :: operator+, -, /, ++, *, etc.
MyClass& MyClass::operator=(const MyClass&) { . . . }
MyClass obj1, obj2;
obj1 = obj2; // equivalent to obj1.operator=(obj2);
- **Global Functions**
- Don't belong to a particular class but, if needed, to access the attributes of a class [friend functions](#ff) can be used
- Operand on the right must be an object of a class where the operator overloading function is implemented
non-static function is needed since they need specific objects to operate on<return type> operator<operator symbols>(<parameters...>) void operator+(int x, MyNumClass& num)
using namespace std;
class Point { public: int x, y; Point(int px, int py){x = px; y = py;} };
istream& operator>>(istream &is, Point& p) { is >> p.x >> p.y; return is; } // operator overloading implementend using a Global function
ostream& operator<<(ostream & os, const Point& p) { os << "[" << p.x << "," << p.y << "]" << endl; return os; }
main() {
Point p(7,17);
cin >> p; // this is equivalent of calling -> operator>>(cin, p); as it were a regular function
cout << p; // this is equivalent of calling -> operator<<(cout, p);
}
bool MyClass::operator!(void) { . . . }
MyClass obj;
if(!obj) // equivalent to if(obj.operator!())
{
. . .
}
bool operator!(const MyClass& refArg) { . . . } // or bool MyClass::operator!(const MyClass objArg) { . . . }
MyClass obj;
if(!obj) // equivalent to if(operator!(obj))
{
. . .
}
bool MyClass::operator>(const MyClass& refObj) { . . . }
MyClass obj1, obj2;
if(obj1 > obj2) // equivalent to if(obj1.operator>(obj2))
{
. . .
}
bool operator>(const MyClass& refObj1, const MyClass& refObj2) { . . . }
MyClass obj1, obj2;
if(obj1 > obj2) // equivalent to if(operator>(obj1, obj2))
{
. . .
}
new operatornew operator in a class to customize memory allocation for example to allocate memory
from a custom memory pool instead of the free store, this means a special memory pool for our application
#include <new>
#include <iostream>
using namespace std;
//Allocator class
class MyAllocator {
public:
MyAllocator() {}
~MyAllocator() {}
static void* operator new (size_t size);
static void operator delete (void *p);
};
void* MyAllocator::operator new (size_t size) {
void* p = malloc(size);
if (p == NULL) {
std::bad_alloc exception;
throw exception; // Throw bad_alloc.
}
cout << "MyAllocator::operator new called with size_t " << size << endl;
return p;
}
void MyAllocator::operator delete (void* p) {
cout << "MyAllocator::operator delete called. " << endl;
delete[] p;
}
int main() {
MyAllocator *p = new MyAllocator; //Create MyAllocator object.
delete p; //Delete MyAllocator object.
return 0;
}
It's a code reutilization technique that allows to create new SW components from existing ones. It allows them to obtain all or certain attributes and methods of an already defined component without the need to duplicate code
base class == super class == parent class
sub class == derivative class == child class
Constructors and destructors are not inherited in the same way as the other methods, they are available to the derivative class but in general their own versions must be implemented
public:
private
protected
class ChildClass : <inheritance_type> ParentClass {
. . .
};
class MyDerivClass : public MyBaseClass {
. . .
};
virtual & non-virtual functionsnon-virtual functionsnon-virtual functions the reference and/or pointer is the one that decides the members/methods to be accessedvirtual modifier are considered in general non-virtual functions and when we call them using a pointer or a reference is when Polymorphism can happennon-virtual functions using an object that DOES NOT inherit from another class (E.g. MyClass Obj; Obj.print()) Polymorphism CANNOT occur
class BaseClass {
public:
BaseClass() { ... }
void print(void) { ... }
};
class DerivClass public: BaseClass{
public:
DerivClass() : BaseClass() { ... }
void print(void) { ... }
};
DerivClass dObj;
BaseClass* bPtr = &dObj;
bPtr->print(); // if 'print' is NOT virtual, this calls function implemented in the BaseClass
virtual functionsvirtual modifier the object that is being referenced in the call is the one that determines which method will be called,
it doesn't matter what type of pointer or reference we are usingvirtual modifiers are only added in the functions prototypes (in the .hpp file) not needed in the function implementation (.cpp file)BaseClassName::FunctionName()
class BaseClass {
public:
BaseClass() { ... }
virtual void print(void) { ... }
};
class DerivClass public: BaseClass{
public:
DerivClass() : BaseClass() { ... }
void print(void) { ... }
};
DerivClass dObj;
BaseClass* bPtr = &dObj;
bPtr->print(); // if 'print' IS virtual, this calls function implemented in the DerivClass
virtual functionsvirtual function is a function that is NOT implemented in base class and forces the derivative class to implement itvirtual functions can or cannot be implemented and give the option to the derivative class to overwrite the functionality
or not but pure virtual functions MUST be implemented in the derivative class or it will produce a compilation errorvirtual functions is called an abstract class, usually used as the top of a classes hierarchy
to force classes that inherit from it to implemented a certain interface (set of functions)
class MyAbsClass {
public:
MyAbsClass() { ... }
virtual void print(void) = 0; // pure virtual function
};
virtual destructorsvirtualvirtual functions it's destructor should be declared as virtual (although there could be exceptions)virtual destructor in the base class, you ensure that the correct destructor is always called when you delete an objectC++ supports multiple inheritance, these means we can inherit form multiple classes and can be implemented with regular inheritance syntax or with templates (not very common to be implemented with templates but achieves equivalent results)
With multiple inheritance it exists the possibility of the diamond problem which can be solved by adding thevirtual keyword when declaring inheritance of a class to make it explicit that what determines which method will be called is the object being referenced
#include <iostream>
using namespace std;
class A { public: void printName(void) { cout << "Class A" << endl; } };
// Removing the virtual identifier when declaring inheritance in classes A and B
// should cause errors due to calling ambiguity when trying to invoke printName()
// It is equivalent to declaring all the methods with the virtual modifier
class B: public virtual A { public: void printName(void) { cout << "Class B" << endl; } };
class C: public virtual A { public: void printName(void) { cout << "Class C" << endl; } };
// BC presents the diamond problem because it inherits from B and C
// which at the same time each inherits from A creating an inheritance "diamond"
class BC: public B, public C { public: void printName(void) { cout << "Class BC" << endl; } };
int main(int argc, char *argv[]) {
BC bcObj;
bcObj.printName(); // calls printName method from BC class due to virtual inheritance
}
<cast_type><variable_type>(variable)static_cast<type>(variable) operator.
This is referred as Static Cast and is used to convert from one type to another and the user has to ensure the type cast is safe.
This is usually used to convert a pointer from a base class to a derived class and from a derived class to a base classMyDerived* md = new MyDerived(); MyBase* mb2 = static_cast<MyBase*>(md); // Safe cast since MyDerived Contains MyBase public members from inheritance.
const modifier to a variable this allows the developer to make a non-modifiable variable
modifiable or a modifiable variable non-modifiable, also to change a variables volatile modifier.
Also sometimes needed to call a method/function that doesnt use const and you want to pass a constconst int MYCONST = 5; volatile int myvolatile = 9; int* nonconst = const_cast<int*>(&MYCONST); int* nonvolatile = const_cast<int*>(&myvolatile);
UnRelated* urc = new UnRelated(); // Very likely unsafe cast because type UnRelated is not related to MyBase class MyBase* rcast = reinterpret_cast<MyBase*>(urc);
cast/casting Operator overloading & Conversion constructorsexplicit keyword is used to specify a conversion constructor or function cannot be used for implicit conversions
so it is mainly used to declare a conversion constructor can only be used for explicit conversions.
MyClass::operator char*() const { . . . }
myClass::operator double() { return 3.1416; }
MyClass obj;
static_cast <char*>(obj); // equivalent to obj.operator char*()
static_cast <double>(obj); // equivalent to obj.operator double() or (double) obj;
double xd = 2.241234;
int xi = static_cast<int>(xd); // equivalent to int xi = (int) xd; in C
Since any constructor with only one argument can be interpreted by the compiler as a conversion constructor and called in certain situations without us being aware we can use the reserved word
explicitto avoid this situation and stop the the compiler from implicitly calling the constructor
dynamic_cast<DerivClassA*>(basePtr) if basePtr points to a DerivClassA object it returns address of that object (pointer of type DerivClassA) if not returns 0/nullptr instead;
Person *basePtr;
Employee* dynPtr;
basePtr = new Student ("Student", 23, "School"); // if this line is active basePtr points to an 'Student' object
//// or
//basePtr = new Employee ("Employee", 25, "Company"); // if this line is active basePtr points to an 'Employee' object
dynPtr = dynamic_cast<Employee*>(person); // returns '0'/nullprt/NULL if not pointing to 'Employee'/'Student' object
if(dynPtr == nullptr) {
std::cout << "basePtr is NOT pointing to an Employee/Student object" << std::endl;
} else {
std::cout << "basePtr IS pointing to an Employee/Student object" << std::endl;
std::cout << "You can now access that object through the dynPtr pointer as well" << std::endl;;
}
autoauto varsauto is used to let the compiler determine the appropriate type for a variable based on the context of it's initialization (type inference)auto ignores const and reference qualifier, if a reference is assigned to an auto variable a copy is created and assigned to the auto var
auto str1 = "Hello"; // equivalent const char str1[] = "Hello"
auto str2 = "Hello"s; // equivalent std::string char str1 = "Hello"
const int& x{6};
auto y=x;
y++; //y==7 x==6 at this point
const auto& y = x;
The C++ standard library provides an exception base class that can be derived and allows us to override the what()
method to return a custom error message string and also override it's virtual destructor in case we want to release memory
If you define an ellipsis (...) as the parameter of an exception handler then it will catch any exception type that is thrown in
its associated try-block. This is most often used as a default exception handler when no other exception handler type matches.
An exception is uncaught if there is no associated exception handler to catch it. When this happens a call to terminate()
is done automatically and any subsequent calls to termination functions that would normally be done during normal program execution does not happen,
this includes calls to allocated objects destructor's functions.
In general it is not considered good practice to throw exception in an objects destructor because it could cause unhandled exceptions. E.g.
if an object is declared inside a try statement and another exception occurs there, when destroying the object for going out of scope
the destructor will be called and if it throws another exception this will be an unhandled exception
#include <iostream>
#include <exception>
using namespace std;
class derivedexception: public exception {
virtual const char* what() const throw() { return "My derived exception"; }
} myderivedexception;
int main () {
try { throw myderivedexception; }
catch (derivedexception& e) { cout << e.what() << '\n'; }
catch (...) { cout << "All other exception types." << endl; }
}
void myfunction() noexcept; //Function does not throw exception, equivalent to noexcept(true) void myfunction() noexcept(true/false); //Throws an exception depending on boolean true/false. true -> does NOT throw, false -> throws void myfunction(void pfa() noexcept); // g takes a pointer to function that doesn't throw void myfunction() throw (); // Old way (before C++11) to specify that throws exception void myfunction() throw (class_name); // Old way (before C++11) to specify that throws exception of specific class usually a class that inherits from `exception`
int x {100}; // 100 is an r-value and x is an l-value
int y = x + 100 // (x+100) is an r-value and y is an l-value
int m = max(x,y) // max(x,7) is an r-value and m is an l-value
int square (int &n) {
return n*n;
}
int num {10};
square(num); // OK
square(5); // Error can't reference rvalue 5
T& lvalue; lvalue reference
T&& rvalue; rvalue reference
prvalue: The C++ library provides a template function called move. Which works more like a type cast.
It's used to tell the compiler to use an object as if it were an rvalue, which means that it makes it moveable.
template<typename T> or template<class T> to define a template function or class where T specifies the type that will be varied, using either option is equivalent but the template<class T> is usually used for classes just for clarity, to the compiler they mean the samedoubles and floats can only be passed as pointers and not by value as defined by the C++ standardTemplates are determined at compile time, so actually the compiler is generating all the necessary code and including it for us
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <iterator>
using namespace std;
const double pi = 3.1415926535897;
class Circle {
public:
Circle(int rad) : radius(rad) { area = pi*radius*radius; }
const bool operator < (const Circle &r) const { return (area < r.area); }
friend std::ostream& operator<< (std::ostream& stream, const Circle& cir) { stream << cir.area << "\n"; return stream; }
private:
int radius; double area;
};
template<typename T>
void printTypeName(T x) {
cout << typeid(x).name() << endl;
}
template<typename TContainer>
void bubbleSort(TContainer begin, TContainer end)
{
TContainer i, j;
for ( i = begin; i != end; i++) {
//Loop around all elements in container.
for ( j = begin; j != i; j++) {
//Loop around container comparing current element to all others and bubble up.
if (*i < *j) {
//Swap elements.
std::swap(*i, *j);
}
}
}
}
int main() {
int myint = 5;
printTypeName<int>(myint);
printTypeName<>(myint);
printTypeName(myint);
Circle c(7);
printTypeName(c);
vector<Circle> circleVec;
circleVec.push_back(Circle(5));
circleVec.push_back(Circle(4));
circleVec.push_back(Circle(3));
circleVec.push_back(Circle(2));
circleVec.push_back(Circle(1));
bubbleSort(circleVec.begin(), circleVec.end());
for (vector<Circle>::iterator it = circleVec.begin(); it != circleVec.end(); it++) {
cout << *it;
}
return 0;
}
#include <iostream>
using namespace std;
template<class T = int>
class Point{
public:
Point() {}
Point(T x, T y): px(x), py(y) {}
private:
T px;
T py;
};
template<class T1, class T2, int size = 1>
class MultiPoint{
public:
Point() {}
Point(T1 x, T2 y): px(x), py(y), s(size) {}
private:
T1 px;
T2 py;
int s;
};
int main() {
MultiPoint<int, double, 3> myPoint(1, 3.1415161);
}
Normally when we write a template class or function we want to use it with many different types, however sometimes we want to code a function or class to make use of a particular type more efficiently this is when we use a template specialization.
To define a specialized template we leave the parameters empty like template<> this is used if we define a template function
but then we want to have an overloaded "specialized" function for an specific type
// Template function for most cases
template<typename T>
void printFunction(T arg) {
cout << "printFunction arg is type " << typeid(arg).name() << " with value " << arg << endl;
}
// Specialized template for integers (for type 'int')
template<>
void printFunction(int intarg) {
cout << "printFunction specialization with int arg only called with type " << typeid(intarg).name() << " with value " << intarg << endl;
}
// Template class for most cases
template<class T>
class MyClass {
public:
MyClass(T initVal) { myMember = initVal; cout <<"My Class template " << myMember << endl;}
private:
T myMember;
};
// Specialized Template class for integers (for type 'int')
template<>
class MyClass <int> {
public:
MyClass(int initVal) { myMember = initVal; cout <<"My Class specialized template " << myMember << endl;}
private:
int myMember;
};
A container class is used to hold and organize objects of other classes. The containers are implemented as template classes
which allows to be used with many different types. E.g. a vector is a container and can be:
Sequence containers are named so because their elements are accessed sequentially, they are vector, list, deque and array, forward_list (added in C++11)
Associative containers which are designed to provide efficient access to elements by key for example: set, map, multiset and multimap. by default they are ordered but there is an unordered version for each one (unordered_set, unordered_map, unordered_multimap, unordered_multiset)
map and multimap use key-value pairs and in set and multiset the value is the key. Keys must always be unique in all casesAn iterator is an object that allows the traversal of a container
We use the form <type>::iterator to declare an interator where type is the typo of the container
They are basically pointers so we use the * to derefence current element pointed by an interator
We use the begin() & end() methods of a container to get an iterator to the first element and to iterate we use a while loop comparing if begins is less/diffrent from end and increment begin
Types of iterators in C++:
Iterators are used to implement generic algorithms, usually defined as a template function and if they change the elements in the container they will usually define an input and output iterator and copy the input iterator elements to the output iterator to avoid changing the original elements.
#include <iostream>
#include <vector>
#include <list>
using namespace std;
template<class TypeRandIter>
void randomise(TypeRandIter iterBegin, TypeRandIter iterEnd) {
while (iterBegin < iterEnd) {
iter_swap(iterBegin, iterBegin + rand() % (iterEnd - iterBegin)); //randomInteger(iterEnd - iterBegin));
++iterBegin;
}
}
int main(int argc,char* argv[]) {
string str = "Hello";
for (string::iterator itStr = str.begin(); itStr != str.end(); itStr++){
cout << *itStr << ",";
}
cout << "\n\n";
list<int> List = { 34, 77, 16, 2, 35, 76, 18, 2 };
cout << "Calling sort on vector " << "\n";
List.sort();
for (auto it: List) {
cout << it << " ";
}
cout << "\n\n";
cout << "Results after calling randomise are " << "\n";
vector<int> temp(List.begin(), List.end()); // Using constructor that basically builds a new vector of ints
randomise(temp.begin(),temp.end());
for (vector<int>::iterator it = temp.begin(); it != temp.end(); it++) {
cout << *it << " ";
}
cout << "\n\n";
cout << "Print orig list after randomize " << "\n";
for (auto it: List) {
cout << it << " ";
}
}
cbegin(), cend(), crbegin() & crend() return const iteratros and can be used with autobegin() and end() global functions
#include <iostream>
using namespace std;
int main(int argc,char* argv[]) {
string str = "Hello";
// const iterator
string::const_iterator cit;
for (cit=str.begin(); cit!=str.end(); ++cit)
cout << *cit << ",";
cout << "\n\n";
// reverse iterator
string::reverse_iterator rit;
for (rit=str.rbegin(); rit!=str.rend(); ++rit)
cout << *rit << ",";
cout << "\n\n";
// cbegin cend
for (auto it=str.cbegin(); it!=str.cend(); ++it)
cout << *it << ",";
cout << "\n\n";
// global begin end
for (auto it=begin(str); it!=end(str); ++it)
cout << *it << ",";
cout << "\n\n";
}
auto&
for (auto e: str)
cout << e << ","; // cannot modify `str`. `e` is a copy of the element
cout << "\n\n";
for (auto& e: str){
e++; // can modify `str`. `e` is a reference to the element
cout << e << ",";
}
cout << "\n\n";
auto second = begin(str)+1; // it to seconds elementauto last = end(str)-1; // it to last elementauto mid = begin(str)+(end(str)-begin(str))/2; // it to mid element since end(str)-begin(str) gives the number of elements which can be divided 2next takes an interator returns following iterator: auto second = next(begin(str));prev takes an interator returns previous iterator: auto last = prev(end(str));distance returns number of steps to go from first to second argument distance(begin(str),end(str)); // Returns number of elementsadvance moves an iterator by its second argument auto mid = being(str); advance(mid,distance(begin(str),end(str))/2); // Returns number of elementsit >= begin() and it < end() must be true but it==end() is not allowedAn Interface is used to define the behavior of classes without saying how to implement it. In C++ usually implemented using abstract classes. They contain generalizations about the characteristics of related entities
The Command Pattern is considered a behavioral design pattern, It is like an object based version of a call back in which the requester sends a request as an object. Used to connect two object so a call in one object triggers code in another
A Function Object (also known as functors) is an object that behaves like a function meaning it is callable but since it's essentially and object it can also store data. To be callable it defines the call operator (operator())
The Handle-Body pattern allows developers to put implementation (body) and interface (handle) into two classes, then a client uses the handle class to interact with the body class
Nested classes are classes declared inside classes, a nested class is a member of the enclosing class and has the same access rights as other members of the class. This means we can access the members of the enclosing class from the nested class. The enclosing class has no special access to the members of the nested classes
In the Association-Delegation pattern objects of one class are connected to another class in this association the controlling class does not manage the life cycle of the controlled class, it just uses the controlled class or in other words delegates a request to the controlled object however this controlled object can exist without the controlling object.
The Proxy pattern is used to communicate with another object that for some reason cannot be communicated with directly, the proxy is placed in between the client and the final destination for the communication.
A Member Function Pointer holds the offset of the function address in the objects list of functions, while a normal function pointer holds the address of the function to call. If it is a virtual function then it is an offset into the virtual table of function pointers.
return_type (className::*memberFunctionPtrName)(parameter_types) = &className::member_function_name; while a normal function pointer: return_type (*FunctionPtrName)(parameter_types) = &function_name;
class Base {
public:
virtual void sayHello(string s) { cout << "Hello from Base class" << s << endl; }
};
class Derived : public Base {
public:
virtual void sayHello(string s) { cout << "Hello from Derived class" << s << endl; }
};
...
void (Base::*baseFuncPtr)(string) = &Base::sayHello;
void (Derived::*derivedFuncPtr)(string) = &Derived::sayHello;
Base baseObj;
Derived derObj;
string str = "My String!";
(baseObj.*baseFuncPtr)(str); // call Base::sayHello
(derObj.*derivedFuncPtr)(str); // call Derived::sayHello
(derObj.*baseFuncPtr)(str); // call Derived::sayHello using base pointer and derived object.
#include <iostream>
#include <string>
using namespace std;
// .hpp
class Singleton {
public:
static Singleton* getSingleton() {
if (!instance) { // Only allow one instance of class to be generated.
instance = new Singleton;
}
return instance;
}
void sayHello(string str) {
cout << "Hello from singleton \n" << str;
}
private:
Singleton() {} //Private so cannot be invoked.
Singleton& operator=(Singleton const& rhs) {} //Private so cannot be invoked.
Singleton(Singleton const& ) {};
static Singleton* instance;
};
//.cpp Init Static member instance;
Singleton* Singleton::instance = NULL;
// main.cpp
int main(int argc, char* argv[]) {
//Get instance create single object.
Singleton::getSingleton()->sayHello("Hello world!!! \n");
return 0;
}
std::shared_ptrstd::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer.
They wrap a raw pointer in a class so that when the class object is destroyed the destructor of the smart pointer object could also release the memory pointed by the raw pointer in case no on else is holding a reference to this memory, this helps avoiding memory leaks and allows smart pointers to be used for garbage collection.
Although they are objects, the std::shared_ptr class defines the operator* and operator->
to overload the dereference (*) and indirection (->) operators, so we can use smart pointer objects as regular pointers
class Test {
public:
Test(int a = 0 ) : m_a(a) {}
~Test() { cout << "Calling destructor for Object with address: " << this << " with value " << m_a << endl; }
public:
int m_a;
};
shared_ptr<Test> sptr(new Test(5));
cout<< "Count of sptr before other reference assigment " << sptr.use_count() << " " << sptr->m_a << endl;
{
shared_ptr<Test> optr = sptr;
cout<< "Count of sptr after other reference assigment " << sptr.use_count() << " " << optr->m_a << endl; // optr->m_a to prove optr points to the same object than sptr
}
cout<< "Count of sptr after other reference goes out of scope " << sptr.use_count() << " " << sptr->m_a << endl;
Streams are essentially a sequence of bytes that are sent from device to device
C++ defines a standard iostream library because input/output operations in C++ occur in streams
cin, cout and cerr are predefined objects in the std namespace
cin is an instance of the istream class, and allows you to perform input from the stdin device.cout is an instance of the ostream class, and allows you to perform output to the stdout device.cerr is another instance of the ostream class, and allows you to perform output to the stderr device.istream and ostream aren't actually classes in their own right, they are typedefs (i.e. aliases)
that represent character-based instantiations of the basic_istream and basic_ostream template classes
std::endl is a manipulator which tells the stream to output an end-of-line#include <iomanip> // Necessary for parameterized manipulators. #include <iostream> // Necessary for general stream I/O definitions. ... std::cout << std::left << std::fixed << std::setw(8) << -123.45 << std::endl; std::cout << std::scientific << -123.45 << std::endl; std::cout.unsetf(std::ios::fixed | std::ios::scientific);
<fstream>std::ifstream inherits from std::istream, and allows you to read data from a file using the >> operator.std::ofstream inherits from std::ostream, and allows you to write data to a file using the << operator.std::fstream inherits from both std::istream and std::ostream, and allows you to read and write data to/from a file using the >> and << operators.
std::fstream iofile("file2.dat", std::ios_base::binary | std::ios_base::app);

TODO add lambda example
We use the inline keyword to define Inline functions which avoid the overhead associated with traditional function calls,
because every time an inline function is called the compiler will insert the body of the function in that location as opposed to making a function call.
However the inline keyword is a compiler directive that is a recommendation only.
The compiler may ignore your request and compile the function normally resulting in function calls anyway.
Static class members are defined using the keyword static, if a member is declared static then it is shared by all the objects of the class.
Likewise a static function member is independent of all the objects, they can be accessed using the class name and the scope operator ::.
Static member functions can only access static data members, static functions and other functions outside the class.
Usually declared in the class definition (.hpp) e.g. private: static int count; and initialized in the implementation file (.cpp) using the scope operator (::), e.g. int Counter::count = 0;
Ambiguity only leaves work to the compiler to define that ambiguity
the thread_local modifier was defined as part of the C++11 standard, it declares that a variable is only accessible on the thread
in which it is created. This prevents sharing of the identifier across multiple threads in the same application.
The OS can use various methods to provide memory to an application when it requests more, such as swapping where it uses a portion of storage space on the fixed disk to move data and programs out of main memory and to the local disk, in order to permit a running application to have memory resources
The mutable keyword is used to declare that a data member can be assigned a value and it can only be applied to non static and non const members.
In general all variables are mutable, an example usage would be if you have a const object but need to be able to modify one of its data members we can declare it mutable and then we are able to change its value
In C++11 we have the alignas and alignof keywords, alignas allows us to align a variable to a multiple number of bytes
(which can make cache read/writes more efficient because when memory is read by the CPU it reads it in as multiples of word size)
and alignof gives us alignment of a variable in bytes.
In general we cannot use the address operator (&) on a variable declared with keyword register because we have told the compiler to keep
the variable in the register and not in the memory. Therefore, there is no memory address for the variable. However using the register
keyword does NOT guarantee the compiler will keep the variable in the register
printfIf you find the information in this page useful and want to show your support, you can make a donation
Use PayPal
This will help me create more stuff and fix the existent content...