C++


Creative Commons License
This C++ tutorial is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
Preamble
This tutorial is about key features of C++. Please note that some features are supported from C++11, C++14 or C++17 only. You may also look at this blog, which sums up the key novelties brought out from C++11.
Headlines
In C++, types are primitive (bool with false and true as possible values), char, wchar_t, char16_t, char32_t, short (at least 16-bit long), int, long (at least 32-bit long), long long (at least 64-bit long), float and double or, they are constructed as data structures by means of the struct, union and class keywords. In modern programming, only the class keyword should be used since struct and union are old-fashioned C style.
Rule(s)
Example
auto x = 0; // 'x' has type 'int' because '0' is by default of type 'int'
auto c = 'a'; // 'char'
auto d = 0.5; // 'double'
auto national_debt = 14400000000000LL; // 'long long'
Resource(s)
N_INSEE.C++.zip 
See also
Java types
http://en.cppreference.com/w/cpp/language/types
Historically, C++ arrays are managed as pointers. However, C++ tends to increase static checking that prevents old-fashioned forms. Otherwise, Java primitive arrays have elements, whose type may be primitive or not.
Example
char* given_name = {'F','r','a','n','c','k'}; // Old style, probable compilation error in C++14!         
char given_name[] = {'f','r','a','n','c','k'}; // Better!
given_name[0]='F';
Rule(s)
Example
T tab[1000]; // Fixed capacity
// Alternatively:
T tab[]; // Variable capacity
tab = new T[1000] // Allocation of memory
delete[] tab; // Full desallocation of memory while 'delete[500] tab;' is a partial desallocation because '500' < '1000'
Resource(s)
N/A
See also
Java arrays
In C++, enumerated types raise the problem of matching to int. Recent improvements occur through scoped enumerated types.
Example (non-scoped)
class Temperature {
public:
    enum Temperature_unit {Celsius, Fahrenheit, Kelvin};
    …
};
Example (scoped)
enum class Medal {Gold, Silver, Bronze};
// Incorrect: 'Medal award = Gold;'
Medal award = Medal::Gold;
// Incorrect (matching to 'int'): 'int i = Medal::Gold;'
Example (remove int as base type)
enum class Direction : char {East, South, West, North};
assert(sizeof(Direction) == 1);
Resource(s)
Exception_management.C++.zip 
See also
Java enumerated_types
http://blog.smartbear.com/c-plus-plus/closer-to-perfection-get-to-know-c11-scoped-and-based-enum-types/
In C++, constructed types (a.k.a. data structure implementations) rely on the class keyword (struct raises the problem of having attributes visible from outside).
Example
std::time_t now = std::time(&now); // '#include <ctime>'
std::tm *now_as_data_structure = std::gmtime(&now);
int year = now_as_data_structure->tm_year + 1900; // Caution: 'tm_year' returns the current year minus '1900'!
Rule(s)
Example
class Program {
    Temperature _target_temperature;
    std::tm _time; // 'std::tm' is an old C data structure that requires '#include <ctime>'
}

class Programmable_thermostat {
private:
    Program _program[8]; // An attribute named '_program' as an array of 8 values, each having 'Program' as type
    …
Resource(s)
Leap_year.C++.zip 
Exception_management.C++.zip 
See also
Java constructed types
In OO programming, attributes aim at being hidden (Parnas' information hiding principle) to avoid any direct (unsafe) access from any code outside the class. Instead, functions are generally exposed. Only internal (reusable) computations are hidden, leading to inherent (“private”) functions. In this spirit, the Smalltalk programming language philosophy is interesting: attributes are by default not accessible while functions are. To create some access (read and/or write), getters and setters are required.
Example (Smalltalk)
get_x
    "return of _x"
    ^_x.
set_x: x
    "assign _x with x"
    _x := x.
Rule(s)
Example
// '.h' file
class My_class {
    public:
        My_class(float = 0.F); // This is imposed by the necessity of defining the value of the 'b' constant!
        float a; // To be avoided, absolutely!
        const float b; 
    private:
        double _c;
    …
};

// '.cpp' file(s):
My_class::My_class(float my_f) : b(my_f) { … // 'b' constant setup

My_class mc;
mc.a = 1.F; // OK because 'public:'
mc.b = 2.F; // Compilation error because 'const'
std::cout << mc.b << std::endl; // OK because 'public:'
mc._c = 3.; // Compilation error because 'private:'
std::cout << mc._c << std::endl; // Compilation error because 'private:'
Rule(s)
Example
// '.h' file
class My_class {
    …
    private:
        void _f();
    public:
        void g(); // '_f' is probably called inside 'g' and/or in another method…
};

// '.cpp' file:
My_class mc;
mc._f(); // Compilation error because 'private:'
mc.g(); // OK because 'public:'

Class attributes and functions

Rule(s)
Example
// '.h' file:
class Temperature {
public:
    static const float Min;
    …
};

// '.cpp' file:
const float Temperature::Min = -273.15F; // In Celsius

if(_value < Min) … // Or 'Temperature::Min' when one accesses this (public) attribute from outside the 'Temperature' class
Rule(s)
Example
// '.h' file:
class Leap_year_utility {
private:
    std::tm _time; // '#include <ctime>'
public:
    static int January();
    int february() const;
    …
    bool leap_year() const; // Result depends on '_time'
};

// '.cpp' file:
int Leap_year_utility::January() {
    return 31;
}
int Leap_year_utility::february() const {
    return leap_year() ? 29 : 28;
}
…
Resource(s)
N/A
See also
Java class attributes and methods
Visibility and encapsulation are such that the hidden part is called “the implementation” while the visible part is called “the interface”. Visibility possibilities are based on the private, protected (in relation with inheritance) and public keywords. However, C++ keeps weaknesses by letting developers to deliberately break encapsulation rules.
Example (non-encapsulation)
#include <cstdio>
#include <ctime>

int main(int argc, char** argv) {

    std::time_t t = 0L; // One refers to the 'long' primtive type, which means "non-encapsulation" -> very bad idea!
    std::printf(std::asctime(std::gmtime(&t))); // January 1, 1970, 00:00:00 GMT
    t = -1L; // That's the reason why encapsulation is important. Doing this is permissive -> again, very bad idea!
    std::printf(std::asctime(std::gmtime(&t))); // This may work, but…

    return 0;
}

Variations on visibility

Rule(s)
Example
// '.h' file:
class Real {
    private: // "implementation" part
        std::vector<char> _implementation; // Machine-based representation through a predefined type, i.e., 'std::vector' ('char' plays the role of byte)
    public: // "interface" part
        Real(std::string); // To create huge 'Real' objects beyond 'double' capacity
    …
};

// '.cpp' file:
Real r("99999999999999999999999999999999999999999999999999999");
Rule(s)
Example
// '.h' file:
class Prisoner {
    private:
        const std::string _file_number;
    public:
        Prisoner(const std::string&);
        bool equals(const Prisoner&) const;
};

// '.cpp' file:
Prisoner::Prisoner(const std::string& file_number) : _file_number(file_number) {
}

bool Prisoner::equals(const Prisoner& p) const {
// 'std::string' comparison: http://en.cppreference.com/w/cpp/string/basic_string/compare
    if (this->_file_number.compare(p._file_number) != 0) return false; // No compilation error while '_file_number' is a priori inaccessible!
    return true;
}

Friend functions

Rule(s)
Example
// '.h' file:
#ifndef _Friend_h
#define _Friend_h

#include <string>

class B; // Forward reference

class A {
public:
    void f(const B&) const;
};

class B {
    int _i;
    friend void A::f(const B&) const;
};

class Reader; // Forward reference

class Phrase; // Forward reference

class Expression {
    std::string _content;
public:
    Expression(const std::string&);
private:
    std::string _read() const;
    friend Phrase operator+(const Phrase&, const Expression&); // Here, the '+' operator is not a member function
    friend class Reader;
};

class Phrase {
    const std::string _content;
public:
    Phrase(const std::string&);
    friend Phrase operator+(const Phrase&, const Expression&); // Here, the '+' operator is not a member function
    friend class Reader;
};

class Reader {
public:
    std::string read(const Expression&) const;
    std::string read(const Phrase&) const;
};

#endif
// '.cpp' file: 
#include <iostream>

#include "Friend.h"

void A::f(const B& b) const {
    b._i;
}

Expression::Expression(const std::string& s) : _content(s) {
}

std::string Expression::_read() const {
    return _content;
}

Phrase::Phrase(const std::string& s) : _content(s) {
}

Phrase operator+(const Phrase& p, const Expression& e) {
    Phrase result(p._content + e._read()); // Access to properties of 'Expression' and 'Phrase'
    return result;
}

std::string Reader::read(const Expression& e) const { // Access to private properties of 'Expression'
    return e._content;
}

std::string Reader::read(const Phrase& p) const { // Access to private properties of 'Phrase'
    return p._content;
}

int main(int argc, char** argv) {
    Reader FranckBarbier;
    Expression e("Caution! Avoid it... What?");
    Phrase p("The 'friend' keyword... ");
    std::cout << FranckBarbier.read(e) << '\n';
    std::cout << FranckBarbier.read(p) << '\n';
    std::cout << FranckBarbier.read(operator+(p, e)) << '\n';

    return 0;
}
Resource(s)
Encapsulation.C++.zip 
Friend.C++.zip 
Non-encapsulation.C++.zip 
See also
Java visibility and encapsulation
Modifiers are additional information associated with attributes and functions. Their composition is sometimes impossible and/or useless.

Attribute modifiers

High scope: public, private, protected, static and const
Low scope: auto, register, extern, volatile, thread_local, signed and unsigned

Function modifiers

public, private, protected, virtual, virtual and =0 (as suffix), inline, static and const (as suffix)
Resource(s)
Storage-based modifiers
See also
Java modifiers
Compared to Java, the naming space in C++ does not rely on hierarchical directories of the OS.
Example
#include <string>
…
std::string s; // The 'string' type is accessed in an absolute way through its namespace, i.e., 'std'

// Alternatively:
#include <string>
…
using namespace std;
…
string s; // The 'string' type is accessed in a relative way through its namespace
Rule(s)
Example
namespace Franck {
	class C { …
    …
}

namespace Barbier = Franck;

using namespace Barbier; // Or 'using namespace Franck;'
…
C c; // Instead of 'Barbier::C c;'

Source file organization

Rule(s)
Example
// 'Elephant.h' file (declarations):
#ifndef _Elephant // Framing in case of multiple inclusions of this file
#define _Elephant
#include <cstddef> // Predefined entities as 'NULL' or 'nullptr', etc.
… // Other possible inclusions here…
class Elephant {
    static void* _Preallocated_memory;
    …
};
#endif // End of framing

// 'Elephant.cpp' file:
#include <cstddef> // One MUST NOT take into account that 'Elephant.h' already includes '<cstddef>'
… // Other possible standard inclusions here…
#include "Elephant.h" // Access to 'Elephant' class
… // Other possible local inclusions here…
void* Elephant::_Preallocated_memory = nullptr;
Resource(s)
N/A
See also
Java naming space
In C++, multiple constructors may exist while it exists only one destructor without parameters. The latter can declared as virtual (see dedicated section). By default, for any class, C++ automatically generates one destructor and constructor without parameters. Introducing a constructor (with or without parameters), respectively a destructor, erases that generated by C++.
Example
#ifndef _Horner_illustration_h
#define _Horner_illustration_h

class Horner_illustration { // Polynomial evaluation according to different methods
    int _size;
    double* _representation;
public:
    Horner_illustration(int);
    ~Horner_illustration();
    …
};

#endif
Horner_illustration::Horner_illustration(int size) : _size(size) {
    assert(_size > 0);
    _representation = new double[_size]; // 'new' C++ operator
    std::time_t t;
    std::srand(std::time(&t));
    for (int i = 0; i < _size; i++) _representation[i] = (double) std::rand();
}

Horner_illustration::~Horner_illustration() {
    delete[] _representation; // 'delete' C++ operator to cancel effect of 'new' in 'Horner_illustration' constructor
}

Reminder on memory management: what to do and… not to do!

Example
// '.h' file:
class Word {
private:
    char* _implementation;
public:
    Word();
    Word(char*);
    ~Word();
    std::string toString() const; // '#include <string>'
};

// '.cpp' file:
std::string Word::toString() const {
    std::string result(_implementation); // '#include <string>'
    return result;
}

Word::Word() {
    _implementation = new char[1];
    _implementation[0] = 0; // This is the way to create an empty string in C!
}

Word::Word(char* s) {
    _implementation = new char[std::strlen(s) + 1]; // '#include <cstring>'
    std::strcpy(_implementation, s); // '#include <cstring>'
}

Word::~Word() {
    if (_implementation) delete[] _implementation;
}

int main(int argc, char** argv) {
    std::string Franck = "Franck"; // '#include <string>'
    Word* w1 = new Word((char*) Franck.c_str());
    std::cout << w1->toString() << std::endl; // '#include <iostream>'
    delete w1; // OK

    Word w2((char*) Franck.c_str());
    std::cout << w2.toString() << std::endl;
    delete &w2; // Damnation! 

    return 0;
}

Overloading and delegation

Example
// '.h' file:
class Limited_bit_stream {
…
// Constructors' overloading (as in Java, overloading applies to other functions as well):
public:
    Limited_bit_stream();
    Limited_bit_stream(const char[]);
    Limited_bit_stream(Bit_stream_format);
    …
};

// '.cpp' file:
Limited_bit_stream::Limited_bit_stream(const char a_string[]) : Limited_bit_stream() { … // From C++11, constructors may call others: this is named "constructor delegation"
Resource(s)
Alcatel_case_study.C++.zip 
Horner.C++.zip 
See also
Java constructor and destructor notions
Basic C++ operators as +, -, *, /, (),[]… may be contextually redefined for a given type.
Example
// '.h' file:
class Polynomial {
    …
public:
    …
    Polynomial operator *(const Polynomial&) const;
    …
};

// '.cpp' file:
Polynomial a, b;
// 'a' and 'b' are filled…
Polynomial c = a * b; // Alternative notation: 'c = a.operator *(b);'

Redefining new and delete

Example
// '.h' file:
class Elephant {
    static void* _Preallocated_memory;
    …
public:
    void* operator new(size_t) throw (std::bad_alloc);
    void operator delete(void*) throw ();
    …
};

class Mammoth {};

// '.cpp' file(s):
void* Elephant::_Preallocated_memory = nullptr;

void* Elephant::operator new(size_t size) throw (std::bad_alloc) {
    if (_Preallocated_memory) return _Preallocated_memory;
    void *p = std::malloc(size);
    if (p == nullptr) throw std::bad_alloc();
    return p;
}

void Elephant::operator delete(void* p) throw () {
    if (_Preallocated_memory) std::free(_Preallocated_memory);
    _Preallocated_memory = p;
    p = nullptr;
}
…
Elephant* e = new Elephant; // Redefined version of 'new'
if (e != nullptr) delete e; // Redefined version of 'delete'

// Modern C++ allows the allocation of pointers without the need of user-defined deletions:
std::unique_ptr<Mammoth> m = std::make_unique<Mammoth>(); // '#include <memory>' // 'm' is a pointer on a 'Mammoth' object without automatic deletion
const std::type_info& ti = typeid (m); // Effective type is computed based on the 'typeid' operator ('#include <typeinfo>')
std::cout << ti.name() << std::endl;
Resource(s)
New_and_delete_redefinition.C++.zip 
Polynomial.C++.zip 
In C++, initialization and assignment are radically different. Initialization relies on the copy constructor while assignment is the possible redefinition of the = operator.
Example
// '.h' file:
#ifndef _STUDENT_H
#define	_STUDENT_H

class Student {
private:
    const Student* * _my_friends; // 'const Student* _my_friends[];' does not allow later assignment through 'new' in particular
public:
    Student(int = 5);
    Student(const Student&); // Copy constructor
    ~Student(); // Required destructor
    const Student& operator=(const Student&); // Assignment redefinition
};

#endif	/* _STUDENT_H */
// '.cpp' file:
#include "Student.h"

Student::Student(int my_friends_capacity) {
    _my_friends = new const Student*[my_friends_capacity];
}

Student::Student(const Student& s) {
    _my_friends = new const Student*[sizeof (s._my_friends) / sizeof (s._my_friends[0])];
    for (int i = 0; i<sizeof (s._my_friends) / sizeof (s._my_friends[0]); i++) {
        _my_friends[i] = s._my_friends[i];
    }
}

Student::~Student() {
    delete[] _my_friends;
}

const Student& Student::operator=(const Student& s) {
    if (this != &s) { // Weird case: 'Student s; s = s;'
        this->~Student(); // Caution, unreliable code!
        this->_my_friends = new const Student*[sizeof (s._my_friends) / sizeof (s._my_friends[0])];
        for (int i = 0; i<sizeof (s._my_friends) / sizeof (s._my_friends[0]); i++) {
            this->_my_friends[i] = s._my_friends[i];
        }
    }
    return *this;
}

int main(int argc, char** argv) {
    Student Franck(10);
    Student FranckBis = Franck; // Initialization!
    Student FranckTer;
    FranckTer = Franck; // Assignment!
    return 0;
}
Resource(s)
Student.C++.zip 
Inheritance is a foundation of OO programming. The principle behind inheritance is the fact that data structures are extended from existing ones. This amounts to adding attributes (structural inheritance) and/or functions (behavioral inheritance). The reserved keyword in C++ for inheritance is the use of a colon, i.e., :. C++ supports multiple inheritance between classes.
Example of inheritance tree (in French)

Structural inheritance

Example
class Compte_bancaire {
        int _id;
    protected:
        float _solde;
    …

class Compte_cheque : public Compte_bancaire {
    protected:
        float _taux_interet;
        float _seuil;
    …

Behavioral inheritance

Example
class Compte_bancaire {
    …
    public:
        inline int id() const {return _id;} // This function is usable by 'Compte_cheque' objects!
    …

Property extension

Example
// '.h' file:
class Compte_epargne_logement : public Compte_epargne { 
    public:
        const static float Taux_interet; // Fixed rate in the French law
    public:
        virtual float taux_interet() const;
    …

// '.cpp' file:
const float Compte_epargne_logement::Taux_interet = Livret_A::Taux_interet * 2.F / 3.F;
float Compte_epargne_logement::taux_interet() const {
    return Taux_interet;
}
…

Inheritance and constructors

Example
// '.h' file:
class Compte_epargne : public Compte_bancaire {
    protected:
        Compte_epargne(int,float = 0.F);
};

// '.cpp' file:
Compte_epargne::Compte_epargne(int id,float solde) : Compte_bancaire(id,solde) {}

Overriding (redefinition)

Example
// '.h' file:
class Compte_bancaire {
    …
    public:
        …
        virtual float taux_interet() const = 0; // Abstract function
        virtual void appliquer_taux_interet();
};

class Compte_cheque : public Compte_bancaire {
    …
    public:
        …
        virtual float taux_interet() const; // Abstract nature is removed when overriding
        virtual void appliquer_taux_interet(); // Overriding as well
};

// '.cpp' file:
void Compte_bancaire::appliquer_taux_interet() {
    _cumul_interets = _solde * (1.F + (taux_interet() / 100.F));
}
float Compte_cheque::taux_interet() const {
    return _taux_interet;
}
void Compte_cheque::appliquer_taux_interet() {
    if(_solde > _seuil) Compte_bancaire::appliquer_taux_interet();
}

Accessing properties of ancestor classes

Example
// Assumption: 'Daughter' inherits from 'Mother', which inherits from 'Grandmother'. One wants in 'Daughter' to access to 'jewel' (not 'private') in 'Mother':
Mother::jewel;
// One now wants in 'Daughter' to access to 'other_jewel' (not 'private') in 'Grandmother':
Grandmother::other_jewel;

final and override keywords

Rule(s)
Example (inheriting with public from the predefinedstd::stack C++ component (#include <stack>))
template <typename T> class Bound_stack : public std::stack<T> {
private:
    const typename std::stack<T>::size_type _capacity;
public:
    Bound_stack(const typename std::stack<T>::size_type&);
    bool full() const;
    void push(const T&);
};

template <typename T> Bound_stack<T>::Bound_stack(const typename std::stack<T>::size_type& capacity) : _capacity(capacity) {
}

template <typename T> bool Bound_stack<T>::full() const {
    return _capacity == this->size();
}

template <typename T> void Bound_stack<T>::push(const T& t) {
    if (full()) throw "push";
    std::stack<T>::push(t);
}
std::stack<char>* bug = new Bound_stack<char>(1); // 'private' inheritance prevents such an assignment
bug->push('a');
bug->push('b'); // Since 'push' is not virtual in 'Bound_stack' then 'push' from 'stack' (the type of 'bug') is called
delete bug; // 'stack' destructor is called while 'bug' effectively points to a 'Bound_stack' object
Rule(s)
Example (not using final)
class Secret {
private:
    virtual void cypher();
public:
    void send_message();
};

class Hack : public Secret {
private:
    void cypher() override;
};
void Secret::cypher() {
    std::cout << "Secret: let's cypher…" << std::endl;
}
void Secret::send_message() {
    cypher();
}
void Hack::cypher() {
    std::cout << "Hack: let's bypass 'cypher'!" << std::endl;
}
…
Hack* h = new Hack; // Don't forget to use 'delete' later on!
h->send_message(); // 'Hack: let's bypass 'cypher'!' is displayed
Example (using final)
class Secret {
private:
    virtual void cypher() final; // Compilation error in 'Hack' when attempting to override 'cypher'
    …

Inheritance and visibility

Rule(s)
Example
std::string C::format() const {
    // A::_a; // Error because 'A::_a' is 'private'
    // B::_a; // Error because 'B::_a' is 'private'
    // A::_b; // Error because 'class B : private A'
    // A::c; // Error because 'class B : private A'
    return B::_b + B::c + _a + _b + c;
}

std::string D::format() const {
    // A::_a; // Error because 'A::_a' is 'private'
    // B::_a; // Error because 'B::_a' is 'private'
    // C::_a; // Error because 'C::_a' is 'private'
    // A::_b; // Error because 'class B : private A'
    // A::c; // Error because 'class B : private A'
    return C::_b + C::c + B::_b + B::c + _a + _b + c;
}

int main() {
    D* d = new D;
    std::cout << d->format() << std::endl;
    C* c = d;
    std::cout << c->format() << std::endl; 
    // B* b = d; // Error because 'class C : protected B'
    // std::cout << d->format() << std::endl;
    // A* a = d; // Error because 'class B : private A'
    // std::cout << a->format() << std::endl;
    delete d;
    return 0;
}
Resource(s)
Final_override_keywords.C++.zip 
Inheritance_and_visibility.C++.zip 
Inheritance_polymorphism.C++.zip 
See also
Java inheritance
Polymorphism is intimately associated with inheritance. Polymorphism relies on the testing of objects' type at run-time to choose the “right” code. Contrary to Java, polymorphism is by default disabled in C++. The virtual keyword must then be used to enable polymorphism. Otherwise, C++ imposes the use of pointers or references to play polymorphism. References are better than pointers for bringing on polymorphism.
Example (pointers):
Compte_cheque cc(1963,10500.F,2.F,10000.F);
Compte_bancaire* cb = &cc;; // 'cb' points to 'cc' since their mutual types are compatible through inheritance
cb->appliquer_taux_interet(); // 'appliquer_taux_interet' in 'Compte_cheque' is run since the runtime type of 'cb' is 'Compte_cheque'
cb = &cel; // Assumption: 'cel' is a direct instance of 'Compte_epargne_logement'
cb->appliquer_taux_interet(); // Polymorphism again
Example (references):
Compte_bancaire& cb = cc;
cb.appliquer_taux_interet();
cb = cel;
cb.appliquer_taux_interet();
Rule(s)
Example
Animal* a1 = new Cat; // Assumption: 'Cat' directly or indirectly inherits from 'Animal'
Cat c;
Animal& a2 = c;

Polymorphism does not work in a constructor

Example (polymorphism fails):
// '.h' file:
class Note {
    …
private:
    virtual void initialization();
    …
public:
    Note(std::istringstream * const);
    …
};

class Confidential_note : public Note {
    …
private:
    void initialization();
public:
    Confidential_note(std::istringstream * const);
    …
};

// '.cpp' file:
void Note::initialization() {
    …
}
Note::Note(std::istringstream * const source) : _source(source) {
    initialization(); // Contrary to Java, event though 'Note::initialization' is declared 'virtual', polymorphism cannot apply because the call occurs inside the constructor!
}
void Confidential_note::initialization() {
    … // Polymorphic behavior, which may possibly include 'Note::initialization();'
}
Confidential_note::Confidential_note(std::istringstream * const source) : Note(source) {} // One expects that, by polymorphism, 'Confidential_note::initialization' is called -> WRONG!
Example (mandatory adaptation):
// '.cpp' file:
…
Confidential_note::Confidential_note(std::istringstream * const source) : Note(source) {
    initialization(); // One must explicitely call 'Confidential_note::initialization'
}
Resource(s)
Inheritance_polymorphism.C++.zip 
See also
Java polymorphism
A virtual destructor allows the polymorphic call of a destructor. So, the call depends upon the runtime type of the destroyed object.
Example
class Expression {
    …
    virtual ~Expression();
    …
class Sentence : public Expression {
    …
    virtual ~Sentence(); // For descendants of 'Sentence'
    …

// Later on, in '.cpp' file:
char separators[] = {' ', '-'};
Expression* e = new Sentence((char*) "Franck Barbier", separators);
…
delete e; // Good, destructor in 'Sentence' is called!
Resource(s)
Virtual_destructor.C++.zip 
The default and delete keywords may, from C++11, be associated with functions.
Example
class C {
public:
    C() = default; // To prevent verbose writing of 'C::C() {}' in '.cpp' file
    C(int);
    C(const C&) = delete; // C++ default initialization code is thrown away!
    virtual ~C() = default; // To prevent verbose writing of 'C::~C() {}' in '.cpp' file
};

// Later on, in '.cpp' file:
C c1;
C c2 = c1; // Compilation error because copy constructor has been deleted
Multiple inheritance is the possibility of having more than one direct mother class. This mechanism must be considered as tricky, even useless, since many OO languages do not support it. However, it may sometimes become useful in certain situations.
Example
// '.h' file:
class Ornithorhynchus : public Mammal, public Oviparous { …
class Echidna : public Mammal, public Oviparous { …
Rule(s)
Example
class iostream : public istream, public ostream { // This is the standard definition in the '<iostream>' file
    …
};
Rule(s)
Example
class Animal {
    protected:
        std::list<Animal*> _kids;
    public:
        inline void Animal::birth(Animal* animal) {_kids.push_back(animal);} // Here, 'inline' is only for the sake of brevity!
    …

class Mammal : virtual public Animal { …
 
class Oviparous : virtual public Animal { …

Multiple inheritance and visibility

Rule(s)
  • Mixing multiple inheritance and visibility may lead to tricky situations.
Example
class A {
    public:
        virtual void f();
};
class B : public A {
    public:
        virtual void f();
};
class C : A {
    public:
        virtual void f();
};
class D : B,C {
    public:
        void g();
};

// Later on, in '.cpp' file:
void D::g() {
    A* pA1;
    // pA1 = this; // Compilation error because two paths exist from 'D' to 'A'
    pA1 = (B*)this; // Path is chosen, OK
    // pA1 = (C*)this; // Compilation error 'C' inherits from 'A' in a private mode
    pA1->f();
}
Resource(s)
Multiple_inheritance_and_visibility.C++.zip 
See also
Java interface multiple inheritance
C++ supports genericity as Ada, Eiffel, Java…
Example
// 'Simple_genericity.h' file
#ifndef _SIMPLE_GENERICITY_H
#define _SIMPLE_GENERICITY_H

#include <list>

template <typename T> class LIFO {
private:
    std::list<T> _representation;
public:
    bool empty() const;
    void in(const T&);
    T out(); // This returns a copy!
};

template <typename T> bool LIFO<T>::empty() const {
    return _representation.empty();
}

template <typename T> T LIFO<T>::out() {
    if (empty()) throw "empty…";
    T t = _representation.back();
    _representation.pop_back();
    return t;
}

template <typename T> void LIFO<T>::in(const T& t) {
    _representation.push_back(t);
}

#endif	/* _SIMPLE_GENERICITY_H */
// 'main.cpp' file
#include <iostream>
#include <string>

#include "Simple_genericity.h"

class Elephant {
  std::string _name;
public:
  inline Elephant(std::string name) : _name(name) {} // 'inline' is for convenience only!
  inline std::string asString() const {return _name;} // 'inline' is for convenience only!
};

int main(int argc, char** argv) {
  Elephant Babar("Babar"),Jumbo("Jumbo");
  LIFO<Elephant> zoo;

  zoo.in(Babar);
  zoo.in(Jumbo);
  std::cout ≪ "Jumbo goes out since it is the last-in: " ≪ zoo.out().asString() ≪ std::endl;

  return 0;
}
Rule(s)
Example
#include <stack>
…
std::stack<char> stack_of_characters;

Default generic types and values

Example
// At design time:
template<typename T,int default_capacity = 10,typename Default_representation = std::vector<T> > class Priority_queue { // '#include <vector>'
    private:
        Default_representation _representation;
    public:
        Priority_queue(int capacity = default_capacity) : capacity(capacity) { …

// At usage time:
Priority_queue<Task,100,std::deque<Task> > priority_queue; // '#include <deque>'

Advanced array management

Rule(s)
Example
std::vector<char> tab(2); // '#include <vector>'
tab[0] = 'a';
tab[1] = 'b';
// tab[2] = 'c'; // Execution error: out of bounds
tab.push_back('c'); // OK, capacity has been automatically increased
Example
std::vector<std::string> sentence; // '#include <vector>'
// Matrix of integers (caution: space required between '>' and '>'!):
std::vector<std::vector<int> > matrix; // '#include <vector>'

Generic functions

Rule(s)
Example
template<typename T> void f(const T& t) { …
…
char c;
f(c);
Rule(s)
Example
// Sorting:
short tab[] = {13,7,6,4,12,11,8,3};
std::vector<short> vector(tab,tab + 8);
for(int i = 0;i < vector.size();i++) std::cout << "-" << vector[i];
std::cout << std::endl;
std::sort(vector.begin(),vector.end()); // #include <algorithm>
for(int i = 0;i < vector.size();i++) std::cout << "-" << vector[i];
std::cout << std::endl; 
// Σ:
std::cout << std::accumulate(vector.begin(),vector.end(),0) << std::endl; // #include <numeric>
Resource(s)
Hanoi.C++.zip 
Illustration_of_list_map_and_set.C++.zip 
Simple_genericity.C++.zip 
See also
Java genericity
Exception management is a programming style that favors the implementation of a defense strategy when facing up abnormal behaviors, failures or, worst, stronger errors that may come from the OS itself (e.g., no more memory). Promoted by Ada, exception management relies on a self-contained thread of control compared to the “normal” program execution. Exceptions are raised and caught depending upon the chosen defense strategy. In OO programming, exceptions are plain objects and, in C++, they are instantiated from a predefined (extensible) hierarchy of classes.
Rule(s)

Creating new exception types

Example
class Invalid_temperature_exception : std::exception { // '#include <stdexcept>'
    float _value; // In Celsius
public:
    Invalid_temperature_exception(float);
    float value() const;
    const char* what() const throw (); // No exception is intended to be thrown, but 'Global_exception_management::my_unexpected' is called in case of contradiction
};

Declaring exceptions

Example
// '.h' file:
class Temperature {
public:
    enum Temperature_unit {Celsius, Fahrenheit, Kelvin};
    static const float Min;
private:
    float _value; // In Celsius
    float _step;
public:
    float asCelsius() const;
    float asFahrenheit() const;
    float asKelvin() const;
    void increment() throw ();
    void decrement() throw (float, std::bad_exception);
    int operator<(const Temperature&) const;
    int operator<=(const Temperature&) const;
    int operator>(const Temperature&) const;
    int operator>=(const Temperature&) const;
    Temperature();
    Temperature(float, enum Temperature_unit = Celsius) throw (char*, Invalid_temperature_exception, std::bad_exception);
};

// '.cpp' file:
void Temperature::decrement() throw (float, std::bad_exception) {
    _value -= _step;
    if (_value < Min) throw _value;
}

Temperature::Temperature(float value, enum Temperature_unit unit) throw (char*, Invalid_temperature_exception, std::bad_exception) {
    switch (unit) {
        case Celsius: _value = value;
            break;
        case Fahrenheit: _value = (value - 32.F) * 5.F / 9.F;
            break;
        case Kelvin: _value = value + Min;
            break;
        default: throw "Illegal temperature unit";
    }
    if (_value < Min) throw Invalid_temperature_exception(_value);
    _step = 0.0001F;
}

Global management policy setup

Example
// '.h' file:
class Global_exception_management {
public:
    static void my_unexpected();
    static void my_terminate();
};

// '.cpp' file:
void Global_exception_management::my_unexpected() {
    std::cout << "my_unexpected" << std::endl; // Partial exception processing
// Active exception is re-routed:
    throw; // This creates a chain so that an instance of 'std::bad_exception' is thrown whether the failing function has this type in its signature
}

void Global_exception_management::my_terminate() {
    std::cout << "my_terminate" << std::endl; // Ror test only
}

std::set_unexpected(&Global_exception_management::my_unexpected);
std::set_terminate(&Global_exception_management::my_terminate);

Catching exceptions (through references for polymorphism)

Example
try {
    Temperature t(0.F, Temperature::Kelvin); // Instance of 'Invalid_temperature_exception' may be raised or "Illegal temperature unit"
    t.decrement(); // 'float' is actually raised because 't' cannot be set to something less than 'Min'
} catch (void* e) { // Does not match either 'float' nor 'Invalid_temperature_exception' nor "Illegal temperature unit"
    std::cerr << "double: " << e << std::endl;
} catch (char* e) { // Matches "Illegal temperature unit"
    std::cerr << e << std::endl;
} catch (Invalid_temperature_exception& ite) {
    std::cerr << ite.what() << std::endl;
} catch (std::bad_exception& be) { // 'Global_exception_management::my_unexpected' is called before while 'Global_exception_management::my_terminate' is bypassed
    std::cerr << "be: " << be.what() << std::endl;
} catch (…) {
    std::cerr << "Default management";
}
Resource(s)
Exception_management.C++.zip 
See also
Java exception management
Covariance on return types in C++ involves, as polymorphism, pointers (or references).
Example (no covariance)
// 'Covariance.h' file
#ifndef _Covariance_H
#define _Covariance_H

class Human_being {
public:
    virtual const Human_being cloning() const;
};

class Man : public Human_being {
public:
    const Man cloning() const; // Compilation error: virtual function 'cloning' has a different return type ('const Man') than the function it overrides (which has 'const Human_being' as return type)
};

class Woman : public Human_being {
public:
    const Woman cloning() const; // Same type of compilation error
};

#endif	/* _Covariance_H */
Example (covariance)
// 'Covariance.h' file
#ifndef _Covariance_H
#define _Covariance_H

#include <iostream>

class Human_being {
public:
    virtual const Human_being* cloning() const;

    virtual ~Human_being() {
        std::cout << "Human_being";
    }
};

class Man : public Human_being {
public:
    const Man* cloning() const;

    ~Man() {
        std::cout << "-Man";
    }
};

class Woman : public Human_being {
public:
    const Woman* cloning() const;

    ~Woman() {
        std::cout << "-Woman";
    }
};

#endif	/* _Covariance_H */
// 'main.cpp' file
#include <iostream>

#include "Covariance.h"

const Human_being* Human_being::cloning() const {
    std::cout << "'cloning()' in 'Human_being' is called…\n";
    return new Human_being; // Very bad programming because 'delete' must be later called in calling context
}

const Man* Man::cloning() const {
    std::cout << "'cloning()' in 'Man' is called…\n";
    return new Man; // Very bad programming because 'delete' must be later called in calling context
}

const Woman* Woman::cloning() const {
    std::cout << "'cloning()' in 'Woman' is called…\n";
    return new Woman; // Very bad programming because 'delete' must be later called in calling context
}

int main(int argc, char** argv) {
    const Human_being *const FranckBarbier = new Man;
    const Human_being* clone = FranckBarbier->cloning(); // 'cloning()' in 'Man' is called… => covariance, yes!
    delete clone;
    delete FranckBarbier;
    return 0;
}
Resource(s)
Resource: Covariance.C++.zip 
See also
Java covariance
As many languages (C, Java, JavaScript…), C++ allows the possibility of having a variable number of arguments for a function.
Example
// 'Variable_number_of_arguments.h' file
#ifndef _Variable_number_of_arguments_H
#define _Variable_number_of_arguments_H

#include <time.h>

#include <set>

class Human_being {
private:
    tm _birth_date;
public:
    Human_being(int = 01, int = 01, int = 1970);
private:
    std::set<Human_being*> _children;
public:
    void births(Human_being*…); // '…' means that the number of arguments is variable (first style)
    void births(int, Human_being*…); // '…' means that the number of arguments is variable (second style)
};

#endif	/* _Variable_number_of_arguments_H */
// 'main.cpp' file
#include <cstdarg> // 'va_list' type
#include <cstdlib> // 'NULL'

#include "Variable_number_of_arguments.h"

using namespace std;

Human_being::Human_being(int day_of_month, int month, int year) {
    _birth_date.tm_mday = day_of_month;
    _birth_date.tm_mon = month;
    _birth_date.tm_year = year;
}

void Human_being::births(Human_being* child…) { // '…' means that the number of arguments is variable
    va_list children;
    va_start(children, child);
    for (Human_being* e = child; e != NULL; e = va_arg(children, Human_being*)) _children.insert(e);
    va_end(children);
}

void Human_being::births(int nb, Human_being* child…) { // '…' means that the number of arguments is variable
    va_list children;
    va_start(children, child);
    Human_being* e = child;
    for (int i = 0; i < nb; i++, e = va_arg(children, Human_being*)) _children.insert(e);
    va_end(children);
}

int main(int argc, char** argv) {
    Human_being FranckBarbier(11, 01, 1963);
    FranckBarbier.births(new Human_being(6, 12, 1993), new Human_being(15, 4, 1996), new Human_being(22, 2, 2001), NULL);
    FranckBarbier.births(3, new Human_being(6, 12, 1993), new Human_being(15, 4, 1996), new Human_being(22, 2, 2001));
    return 0;
}
Resource(s)
Variable_number_of_arguments.C++.zip 
See also
Variable number of arguments in Java
C++ offers a lightweight infrastructure for introspection, which is called Run-Time Type Information (RTTI). One needs #include <typeinfo> to have an access to this infrastructure.
Example
Vector<int>* pv;
Vector_quadratic_norm<int> vqn, *pvqn;
pvqn = &vqn; // Normal
pv = &vqn; // Contra-variance

//    pvqn = static_cast<Vector_quadratic_norm<int>*> (pv); // Compilation error

pvqn = reinterpret_cast<Vector_quadratic_norm<int>*> (pv); // Unreliable, but this works at run-time because 'pv' points to an instance of 'Vector_quadratic_norm<int>'
const std::type_info& ti1 = typeid (pvqn); // Effective type is computed based on the 'typeid' operator ('#include <typeinfo>')
if (ti1 != typeid (Vector_quadratic_norm<int>*)) throw std::bad_typeid(); // Exception type through '#include <typeinfo>'
std::cout << ti1.name() << std::endl;

pvqn = dynamic_cast<Vector_quadratic_norm<int>*> (pv); // Reliable because conversion occurs if and only if types comply with each other
const std::type_info& ti2 = typeid (pvqn);
if (ti2 != typeid (Vector_quadratic_norm<int>*)) throw std::bad_typeid();
std::cout << ti2.name() << std::endl;
Resource(s)
RTTI.C++.zip 
See also
Introspection in Java
C++ supports the notion of function pointer by which any function may be called through a pointer instead of its name.
Example
'.h' file:
#ifndef _Function_pointer_h
#define _Function_pointer_h 

#include <ctime>

class Meal {
public:
    static const std::tm Defaut_moment;

    enum Type {
        Breakfast, Lunch, Afternoon_tea, Dinner
    };
private:
    enum Type _type;
    std::tm _moment;
public:
    Meal(enum Type = Breakfast, const std::tm& = Defaut_moment);
    const std::tm& moment() const;
};

#endif
'.cpp' file:
#include <iostream>

#include "Function_pointer.h"

const std::tm Meal::Defaut_moment = {0, 0, 12, 15, 3, 96}; // April 15, 1996

Meal::Meal(enum Type type, const std::tm& moment) : _type(type), _moment(moment) {
}

const std::tm& Meal::moment() const {
    return _moment;
}

int main(int argc, char** argv) {
    time_t clock = std::time(&clock);
    std::tm* now = std::gmtime(&clock);

    Meal m1(Meal::Dinner, *now);
    std::cout << "m1 at " << std::asctime(&(m1.moment())) << "\n\n";

    Meal m2;
    std::cout << "m2 at " << std::asctime(&(m2.moment())) << "\n\n";

    const std::tm & (Meal::*function_pointer)() const; // Pointer declaration
    function_pointer = &Meal::moment; // Pointer assignment
    const std::tm moment = (m1.*function_pointer)(); // Pointer use
    std::cout << "m1 at " << std::asctime(&(moment)) << "\n\n";

    char* (*pointer_asctime)(const std::tm*); // Pointer declaration
    pointer_asctime = &std::asctime; // Pointer assignment
    std::cout << "m2 at " << (*pointer_asctime)(&(m2.moment())) << "\n\n"; // Pointer use

    return 0;
}
Resource(s)
Function_pointer.C++.zip 
See also
N/A
C++ supports the notion of lambda expression that is similar to that of “function objet” or “functor”. This recent mechanism makes that of function pointer deprecated. Simply speaking, functors are common objects that support the redefinition of the () operator, i.e., “the call” of a function.
Example
#include <algorithm> // 'std::for_each'
#include <iostream>
#include <string>

int main(int argc, char** argv) {
    std::string FB = "Franck Barbier";
    auto my_char = 'a';
    auto number_of_my_char = 0;

    // Functor is defined on the fly as JavaScript anonymous functions:
    std::for_each(FB.begin(), FB.end(), [my_char, &number_of_my_char] (const char& c) -> bool {
        if (c == my_char) {
            number_of_my_char++;
            return true;
        }
        return false;
    });
    std::cout << FB + " includes " << number_of_my_char << " occurrences of '" << my_char << "'" << std::endl << std::endl;

    number_of_my_char = 0; // Reset
    // Alternatively, functor may be defined as a common object:
    auto my_functor = [my_char, &number_of_my_char](const char& c) -> bool {
        if (c == my_char) {
            number_of_my_char++;
            return true;
        }
        return false;
    };
    std::for_each(FB.begin(), FB.end(), my_functor);
    std::cout << FB + " includes " << number_of_my_char << " occurrences of '" << my_char << "'" << std::endl << std::endl;

    return 0;
}
Resource(s)
Lambda_expression.C++.zip 
See also
Functional interfaces and lambda expressions in Java