Classes in c++ part 1

Class declaration

Member specification

class S {
    int d1; // non-static data member
    int a[10] = {1,2}; // non-static data member with initializer (C++11)
    static const int d2 = 1; // static data member with initializer
    virtual void f1(int) = 0; // pure virtual member function
    std::string d3, *d4, f2(int); // two data members and a member function
    enum {NORTH, SOUTH, EAST, WEST};
    struct NestedS {
        std::string s;
    } d5, *d6;
    typedef NestedS value_type, *pointer_type;
}

Function definitions

class M {
    std::size_t C;
    std::vector<int> data;
 public:
    M(std::size_t R, std::size_t C) : C(C), data(R*C) {} // constructor definition 
    int operator()(size_t r, size_t c) const { // member function definition
        return data[r*C+c];
    }
    int& operator()(size_t r, size_t c) {  // another member function definition
        return data[r*C+c];
    }
};

 Access specifiers

class S {
 public:
    S();          // public constructor
    S(const S&);  // public copy constructor
    virtual ~S(); // public virtual destructor
 private:
    int* ptr; // private data member
};

Using-declarations

class Base {
 protected:
     int d;
};
class Derived : public Base {
 public:
    using Base::d; // make Base's protected member d a public member of Derived
    using Base::Base; // inherit all parent's constructors (C++11)
};

member template declarations

struct S {
    template<typename T>
    void f(T&& n);
 
    template<class CharT>
    struct NestedS {
        std::basic_string<CharT> s;
    };
};

alias declarations

template <typename T>
struct identity
{
    using type = T;
};

local struct

 
int main()
{
    std::vector<int> v{1,2,3};
    struct Local {
       bool operator()(int n, int m) {
           return n > m;
       }
    };
    std::sort(v.begin(), v.end(), Local()); // since C++11
    for(int n: v) std::cout << n << ' ';
}

injected-class-name

int X;
struct X {
    void f() {
        X* p; // OK. X refers to the injected-class-name
        ::X* q; // Error: name lookup finds a variable name, which hides the struct name
    }
};
struct A {
    A();
    A(int);
    template<class T> A(T) {}
};
using A_alias = A;
 
A::A() {}
A_alias::A(int) {}
template A::A(double);
 
struct B : A {
    using A_alias::A;
};
 
A::A a; // Error: A::A is considered to name a constructor, not a type
struct A::A a2; // OK, same as 'A a2;'
B::A b; // OK, same as 'A b;'

Non-static data members

struct A { int a; char b; };
struct B { const int b1; volatile char b2; }; 
// A and B's common initial sequence is A.a, A.b and B.b1, B.b2
struct C { int c; unsigned : 0; char b; };
// A and C's common initial sequence is A.a and C.c
struct D { int d; char b : 4; };
// A and D's common initial sequence is A.a and D.d
struct E { unsigned int e; char b; };
// A and E's common initial sequence is empty

Member initialization

struct S
{
    int n;
    std::string s;
    S() : n(7) // direct-initializes n, default-initializes s
    { }
};
int x = 0;
struct S
{
    int n = ++x;
    S() { }                 // uses default member initializer
    S(int arg) : n(arg) { } // uses member initializer 
};
 
int main()
{
    std::cout << x << '\n'; // prints 0
    S s1;
    std::cout << x << '\n'; // prints 1 (default initializer ran)
    S s2(7);
    std::cout << x << '\n'; // prints 1 (default initializer did not run)
}
struct X {
   int a[] = {1,2,3}; // error
   int b[3] = {1,2,3}; // OK
};
struct node {
    node* p = new node; // error: use of implicit or defaulted node::node() 
};
struct A
{
    A() = default;          // OK
    A(int v) : v(v) { }     // OK
    const int& v = 42;      // OK
};
A a1;    // error: ill-formed binding of temporary to reference
A a2(1); // OK (default member initializer ignored because v appears in a constructor)
         // however a2.v is a dangling reference
struct S
{
    int m;
    int n;
    int x = m;            // OK: implicit this-> allowed in default initializers (C++11)
    S(int i) : m(i), n(m) // OK: implicit this-> allowed in member initializer lists
    {
        this->f();        // explicit member access expression
        f();              // implicit this-> allowed in member function bodies
    }
    void f();
};
struct S
{
   int m;
   void f();
};
int S::*p = &S::m;       // OK: use of m to make a pointer to member
void (S::*fp)() = &S::f; // OK: use of f to make a pointer to member

Non-static member functions

#include <iostream>
#include <string>
#include <utility>
#include <exception>
 
struct S {
    int data;
 
    // simple converting constructor (declaration)
    S(int val);
 
    // simple explicit constructor (declaration)
    explicit S(std::string str);
 
    // const member function (definition)
    virtual int getData() const { return data; }
 
};
 
// definition of the constructor
S::S(int val) : data(val) {
    std::cout << "ctor1 called, data = " << data << '\n';
}
 
// this constructor has a catch clause
S::S(std::string str) try : data(std::stoi(str)) {
    std::cout << "ctor2 called, data = " << data << '\n';
} catch(const std::exception&) {
    std::cout << "ctor2 failed, string was '" << str << "'\n";
    throw; // ctor's catch clause should always rethrow
}
 
struct D : S {
    int data2;
    // constructor with a default argument
    D(int v1, int v2 = 11) : S(v1), data2(v2) {}
 
    // virtual member function
    int getData() const override { return data*data2; }
 
    // lvalue-only assignment operator
    D& operator=(D other) & {
        std::swap(other.data, data);
        std::swap(other.data2, data2);
        return *this;
    }
};
 
int main()
{
    D d1 = 1;
    S s2("2");
    try {
         S s3("not a number");
    } catch(const std::exception&) {}
    std::cout << s2.getData() << '\n';
 
   D d2(3, 4);
   d2 = d1; // OK: assignment to lvalue
//   D(5) = d1; // ERROR: no suitable overload of operator=
}

nested classes

struct enclose {
    struct inner {
        static int x;
        void f(int i);
    };
};
int enclose::inner::x = 1; // definition
void enclose::inner::f(int i) {} // definition
class enclose {
    class nested1; // forward declaration
    class nested2; // forward declaration
    class nested1 {}; // definition of nested class
};
class enclose::nested2 { }; // definition of nested class
class enclose {
    struct nested { // private member
        void g() {}
    };
 public:
    static nested f() { return nested{}; }
};
 
int main()
{
    //enclose::nested n1 = enclose::f(); // error: 'nested' is private
 
    enclose::f().g(); // OK: does not name 'nested'
    auto n2 = enclose::f(); // OK: does not name 'nested'
    n2.g();
}

Derived classes

Virtual base classes

struct B { int n; };
class X : public virtual B {};
class Y : virtual public B {};
class Z : public B {};
// every object of type AA has one X, one Y, one Z, and two B's:
// one that is the base of Z and one that is shared by X and Y
struct AA : X, Y, Z {
    AA() {
        X::n = 1; // modifies the virtual B subobject's member
        Y::n = 2; // modifies the same virtual B subobject's member
        Z::n = 3; // modifies the non-virtual B subobject's member
 
        std::cout << X::n << Y::n << Z::n << '\n'; // prints 223
    }
};
struct B {
    int n;
    B(int x) : n(x) {}
};
struct X : virtual B { X() : B(1) {} };
struct Y : virtual B { Y() : B(2) {} };
struct AA : X, Y     { AA() : B(3), X(), Y() {} };
 
// the default constructor of AA calls the default constructors of B , X and Y 
// but those constructors do not call the constructor of B because B is a virtual base
AA a; // a.n == 3
// the default constructor of X calls the constructor of B
X x; // x.n == 1
class A{
public:
    A(){
       cout<<"call A\n";
    }
};

class B:virtual public A{
public:
    B(){
        cout<<"call B\n";
    }
};

class C:virtual public A{
public:
    C(){
        cout<<"call C\n";
    }
};

class D: public B,public C{
public:
    D(){
        cout<<"call D\n";
    }
};



int main()
{
    D b;
}

output
call A
call B
call C
call D
without virtual
output
call A
call B
call A
call C
call D

Using-declaration

#include <iostream>
struct B {
    virtual void f(int) { std::cout << "B::f\n"; }
    void g(char)        { std::cout << "B::g\n"; }
    void h(int)         { std::cout << "B::h\n"; }
 protected:
    int m; // B::m is protected
    typedef int value_type;
};
 
struct D : B {
    using B::m; // D::m is public
    using B::value_type; // D::value_type is public
 
    using B::f;
    void f(int) { std::cout << "D::f\n"; } // D::f(int) overrides B::f(int)
    using B::g;
    void g(int) { std::cout << "D::g\n"; } // both g(int) and g(char) are visible
                                           // as members of D
    using B::h;
    void h(int) { std::cout << "D::h\n"; } // D::h(int) hides B::h(int)
};
 
int main()
{
    D d;
    B& b = d;
 
//    b.m = 2; // error, B::m is protected
    d.m = 1; // protected B::m is accessible as public D::m
    b.f(1); // calls derived f()
    d.f(1); // calls derived f()
    d.g(1); // calls derived g(int)
    d.g('a'); // calls base g(char)
    b.h(1); // calls base h()
    d.h(1); // calls derived h()
}
struct B1 {  B1(int, ...) { } };
struct B2 {  B2(double)   { } };
 
int get();
 
struct D1 : B1 {
  using B1::B1;  // inherits B1(int, ...)
  int x;
  int y = get();
};
 
void test() {
  D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4),
                 // then d.x is default-initialized (no initialization is performed),
                 // then d.y is initialized by calling get()
  D1 e;          // Error: D1 has no default constructor
}
 
struct D2 : B2 {
  using B2::B2; // inherits B2(double)
  B1 b;
};
 
D2 f(1.0);       // error: B1 has no default constructor
struct A { A(int); };
struct B : A { using A::A; };
struct C1 : B { using B::B; };
struct C2 : B { using B::B; };
 
struct D1 : C1, C2 {
  using C1::C1;
  using C2::C2;
};
D1 d1(0); // ill-formed: constructor inherited from different B base subobjects
 
struct V1 : virtual B { using B::B; };
struct V2 : virtual B { using B::B; };
 
struct D2 : V1, V2 {
  using V1::V1;
  using V2::V2;
};
D2 d2(0); // OK: there is only one B subobject.
          // This initializes the virtual B base class,
          //  which initializes the A base class
          // then initializes the V1 and V2 base classes
          //  as if by a defaulted default constructor

virtual function specifier

struct A { virtual void f(); };     // A::f is virtual
struct B : A { void f(); };         // B::f overrides A::f in B
struct C : virtual B { void f(); }; // C::f overrides A::f in C
struct D : virtual B {}; // D does not introduce an overrider, B::f is final in D
struct E : C, D  {       // E does not introduce an overrider, C::f is final in E
    using A::f; // not a function declaration, just makes A::f visible to lookup
};
int main() {
   E e;
   e.f();    // virtual call calls C::f, the final overrider in e
   e.E::f(); // non-virtual call calls A::f, which is visible in E
}
class B {
    virtual void do_f(); // private member
 public:
    void f() { do_f(); } // public interface
};
struct D : public B {
    void do_f() override; // overrides B::do_f
};
 
int main()
{
    D d;
    B* bp = &d;
    bp->f(); // internally calls D::do_f();
}

Virtual destructor

class Base {
 public:
    virtual ~Base() { /* releases Base's resources */ }
};
 
class Derived : public Base {
    ~Derived() { /* releases Derived's resources */ }
};
 
int main()
{
    Base* b = new Derived;
    delete b; // Makes a virtual function call to Base::~Base()
              // since it is virtual, it calls Derived::~Derived() which can
              // release resources of the derived class, and then calls
              // Base::~Base() following the usual order of destruction
}

Covariant return types

class B {};
 
struct Base {
    virtual void vf1();
    virtual void vf2();
    virtual void vf3();
    virtual B* vf4();
    virtual B* vf5();
};
 
class D : private B {
    friend struct Derived; // in Derived, B is an accessible base of D
};
 
class A; // forward-declared class is an incomplete type
 
struct Derived : public Base {
    void vf1();    // virtual, overrides Base::vf1()
    void vf2(int); // non-virtual, hides Base::vf2()
//  char vf3();    // Error: overrides Base::vf3, but has different
                   // and non-covariant return type
    D* vf4();      // overrides Base::vf4() and has covariant return type
//  A* vf5();      // Error: A is incomplete type
};
 
int main()
{
    Derived d;
    Base& br = d;
    Derived& dr = d;
 
    br.vf1(); // calls Derived::vf1()
    br.vf2(); // calls Base::vf2()
//  dr.vf2(); // Error: vf2(int) hides vf2()
 
    B* p = br.vf4(); // calls Derived::vf4() and converts the result to B*
    D* q = dr.vf4(); // calls Derived::vf4() and does not convert
                     //  the result to B*
 
}

initialization in c++

Default initialization

struct T1 { int mem; };
 
struct T2
{
    int mem;
    T2() { } // "mem" is not in the initializer list
};
 
int n; // static non-class, a two-phase initialization is done:
       // 1) zero initialization initializes n to zero
       // 2) default initialization does nothing, leaving n being zero
 
int main()
{
    int n;            // non-class, the value is indeterminate
    std::string s;    // class, calls default ctor, the value is "" (empty string)
    std::string a[2]; // array, default-initializes the elements, the value is {"", ""}
//  int& r;           // error: a reference
//  const int n;      // error: a const non-class
//  const T1 t1;      // error: const class with implicit default ctor
    T1 t1;            // class, calls implicit default ctor
    const T2 t2;      // const class, calls the user-provided default ctor
                      // t2.mem is default-initialized (to indeterminate value)
}

Value initialization

T()
new T ()
Class::Class() : member() {  }
T object {};
T{}
new T {}
Class::Class() : member{} {  }

struct T1
{
    int mem1;
    std::string mem2;
}; // implicit default constructor
 
struct T2
{
    int mem1;
    std::string mem2;
    T2(const T2&) { } // user-provided copy constructor
};                    // no default constructor
 
struct T3
{
    int mem1;
    std::string mem2;
    T3() { } // user-provided default constructor
};
 
std::string s{}; // class => default-initialization, the value is ""
 
int main()
{
    int n{};                // scalar => zero-initialization, the value is 0
    double f = double();    // scalar => zero-initialization, the value is 0.0
    int* a = new int[10](); // array => value-initialization of each element
                            //          the value of each element is 0
    T1 t1{};                // class with implicit default constructor =>
                            //     t1.mem1 is zero-initialized, the value is 0
                            //     t1.mem2 is default-initialized, the value is ""
//  T2 t2{};                // error: class with no default constructor
    T3 t3{};                // class with user-provided default constructor =>
                            //     t3.mem1 is default-initialized to indeterminate value
                            //     t3.mem2 is default-initialized, the value is ""
    std::vector<int> v(3);  // value-initialization of each element
                            // the value of each element is 0
    std::cout << s.size() << ' ' << n << ' ' << f << ' ' << a[9] << ' ' << v[2] << '\n';
    std::cout << t1.mem1 << ' ' << t3.mem1 << '\n';
    delete[] a;
}

Direct initialization

T object arg );
T object arg1, arg2, … );
T object arg };
T other )
T arg1, arg2, … )
static_cast< T >( other )
new T(args, …)
Class::Class() : member(args, …) {  }
[arg](){  }
struct B {
  int a;
  int&& r;
};
 
int f();
int n = 10;
 
B b1{1, f()};               // OK, lifetime is extended
B b2(1, f());               // well-formed, but dangling reference
B b3{1.0, 1};               // error: narrowing conversion
B b4(1.0, 1);               // well-formed, but dangling reference
B b5(1.0, std::move(n));    // OK
struct M { };
struct L { L(M&); };
 
M n;
void f() {
    M(m); // declaration, equivalent to M m;
    L(n); // ill-formed declaration
    L(l)(m); // still a declaration
}

Copy initialization

T object = other;
T object = {other;
f(other)
return other;
throw object;catch (T object)
T array[N] = {other};
struct A 
{
  operator int() { return 12;}
};
 
struct B 
{
  B(int) {}
};
 
int main()
{
    std::string s = "test"; // OK: constructor is non-explicit
    std::string s2 = std::move(s); // this copy-initialization performs a move
 
//  std::unique_ptr<int> p = new int(1); // error: constructor is explicit
    std::unique_ptr<int> p(new int(1)); // OK: direct-initialization
 
 
    int n = 3.14;    // floating-integral conversion
    const int b = n; // const doesn't matter
    int c = b;       // ...either way
 
 
    A a;
    B b0 = 12;
//    B b1 = a; //< error: conversion from 'A' to non-scalar type 'B' requested
    B b2{a};        // < identical, calling A::operator int(), then B::B(int)
    B b3 = {a};     // <
    auto b4 = B{a}; // <
 
//    b0 = a; //< error, assignment operator overload needed 
}

Aggregate initialization

T object = {arg1, arg2, …};
T object {arg1, arg2, …};
T object = { .designator = arg1 , .designator { arg2 } … };
T object { .designator = arg1 , .designator { arg2 } … };
T object (arg1, arg2, …);
struct A { int x; int y; int z; };
A a{.y = 2, .x = 1}; // error; designator order does not match declaration order
A b{.x = 1, .z = 2}; // ok, b.y initialized to 0
union u { int a; const char* b; };
u f = { .b = "asdf" };         // OK, active member of the union is b
u g = { .a = 1, .b = "asdf" }; // Error, only one initializer may be provided
struct A { int x, y; };
struct B { struct A a; };
struct A a = {.y = 1, .x = 2}; // valid C, invalid C++ (out of order)
int arr[3] = {[1] = 5};        // valid C, invalid C++ (array)
struct B b = {.a.x = 0};       // valid C, invalid C++ (nested)
struct A a = {.x = 1, 2};      // valid C, invalid C++ (mixed)
char a[] = "abc";
// equivalent to char a[4] = {'a', 'b', 'c', '\0'};
 
//  unsigned char b[3] = "abc"; // Error: initializer string too long
unsigned char b[5]{"abc"};
// equivalent to unsigned char b[5] = {'a', 'b', 'c', '\0', '\0'};
 
wchar_t c[] = {L"кошка"}; // optional braces
// equivalent to wchar_t c[6] = {L'к', L'о', L'ш', L'к', L'а', L'\0'};
struct S {
    int x;
    struct Foo {
        int i;
        int j;
        int a[3];
    } b;
};
 
union U {
    int a;
    const char* b;
};
 
int main()
{
    S s1 = { 1, { 2, 3, {4, 5, 6} } };
    S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision
    S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax
    S s4{1, 2, 3, 4, 5, 6}; // error in C++11: brace-elision only allowed with equals sign
                            // okay in C++14
 
    int ar[] = {1,2,3}; // ar is int[3]
    int ab[] (1, 2, 3); // (C++20) ab is int[3] 
//  char cr[3] = {'a', 'b', 'c', 'd'}; // too many initializer clauses
    char cr[3] = {'a'}; // array initialized as {'a', '\0', '\0'}
 
    int ar2d1[2][2] = {{1, 2}, {3, 4}}; // fully-braced 2D array: {1, 2}
                                        //                        {3, 4}
    int ar2d2[2][2] = {1, 2, 3, 4}; // brace elision: {1, 2}
                                    //                {3, 4}
    int ar2d3[2][2] = {{1}, {2}};   // only first column: {1, 0}
                                    //                    {2, 0}
 
    std::array<int, 3> std_ar2{ {1,2,3} };    // std::array is an aggregate
    std::array<int, 3> std_ar1 = {1, 2, 3}; // brace-elision okay
 
    int ai[] = { 1, 2.0 }; // narrowing conversion from double to int:
                           // error in C++11, okay in C++03
 
    std::string ars[] = {std::string("one"), // copy-initialization
                         "two",              // conversion, then copy-initialization
                         {'t', 'h', 'r', 'e', 'e'} }; // list-initialization
 
    U u1 = {1}; // OK, first member of the union
//    U u2 = { 0, "asdf" }; // error: too many initializers for union
//    U u3 = { "asdf" }; // error: invalid conversion to int
 
}
 
// aggregate
struct base1 { int b1, b2 = 42; };
// non-aggregate
struct base2 {
  base2() : b3(42) {}
  int b3;
};
// aggregate in C++17
struct derived : base1, base2 { int d; };
derived d1{ {1, 2}, { }, 4}; // d1.b1 = 1, d1.b2 = 2,  d1.b3 = 42, d1.d = 4
derived d2{ {    }, { }, 4}; // d2.b1 = 0, d2.b2 = 42, d2.b3 = 42, d2.d = 4

List initialization

struct X {
    X() = default;
    X(const X&) = default;
};
 
struct Q {
    Q() = default;
    Q(Q const&) = default;
    Q(std::initializer_list<Q>) {}
};
 
int main() {
  X x;
  X x2 = X { x }; // copy-constructor (not aggregate initialization)
  Q q;
  Q q2 = Q { q }; // initializer-list constructor (not copy constructor)
}

Reference initialization

T & ref = object ;
T & ref = arg1, arg2, … };
T & ref ( object ) ;
T & ref arg1, arg2, … } ;
T && ref = object ;
T && ref = arg1, arg2, … };
T && ref ( object ) ;
T && ref { arg1, arg2, … } ;
given R fn ( T & arg ); 
or R fn ( T && arg );
fn ( object )fn ( { arg1, arg2, … } )
inside T & fn () or T && fn ()return object ;
given T & ref ; or T && ref ; inside the definition of Class Class::Class(…) : ref( object) {…}
struct S {
    int mi;
    const std::pair<int, int>& mp; // reference member
};
 
void foo(int) {}
 
struct A {};
 
struct B : A {
    int n;
    operator int&() { return n; }
};
 
B bar() { return B(); }
 
//int& bad_r;      // error: no initializer
extern int& ext_r; // OK
 
int main() {
//  Lvalues
    int n = 1;
    int& r1 = n;                    // lvalue reference to the object n
    const int& cr(n);               // reference can be more cv-qualified
    volatile int& cv{n};            // any initializer syntax can be used
    int& r2 = r1;                   // another lvalue reference to the object n
//  int& bad = cr;                  // error: less cv-qualified
    int& r3 = const_cast<int&>(cr); // const_cast is needed
 
    void (&rf)(int) = foo; // lvalue reference to function
    int ar[3];
    int (&ra)[3] = ar;     // lvalue reference to array
 
    B b;
    A& base_ref = b;        // reference to base subobject
    int& converted_ref = b; // reference to the result of a conversion
 
//  Rvalues
//  int& bad = 1;        // error: cannot bind lvalue ref to rvalue
    const int& cref = 1; // bound to rvalue
    int&& rref = 1;      // bound to rvalue
 
    const A& cref2 = bar(); // reference to A subobject of B temporary
    A&& rref2 = bar();      // same
 
    int&& xref = static_cast<int&&>(n); // bind directly to n
//  int&& copy_ref = n;                 // error: can't bind to an lvalue
    double&& copy_ref = n;              // bind to an rvalue temporary with value 1.0
 
//  Restrictions on temporary lifetimes
    std::ostream& buf_ref = std::ostringstream() << 'a'; // the ostringstream temporary
                      // was bound to the left operand of operator<<
                      // but its lifetime ended at the semicolon
                      // so buf_ref is a dangling reference
 
    S a {1, {2, 3} };         // temporary pair {2, 3} bound to the reference member
                              // a.mp and its lifetime is extended to match a
    S* p = new S{1, {2, 3} }; // temporary pair {2, 3} bound to the reference
                              // member p->mp, but its lifetime ended at the semicolon
                              // p->mp is a dangling reference
    delete p;
}

examples

struct A{
    A(int i){

    }
};
struct B{
    B(A a){

    }
};
struct C{
    C(B b){

    }
};
int main(int argc,char* argv[]){
    B b=(A)5;
    B bb(5);
    C c((A)5);
    return 0;
}

Functions in c++

Function Pointer

using namespace std;

int fun(){
    cout<<"call fun";
    return 0;
}
typedef int (*ff)();
using fu=ff;

int main(int _argc,char* _argv[]){
    int(*f)()=fun;
    f();
    (*f)();
    ff fff=(ff)fun;
    fu fu1=fun;
    fu1();
}
class A{
public:
    virtual int fun(){
        cout<<"A";
        return 0;
    }
};

class B:public A{
public:
    int fun() override {
        cout<<"B";
        return 0;
    }
};

typedef int(A::*f)();

int main(int _argc,char* _argv[]){
    f ff=&A::fun;
    A a{};
    B b{};
    (a.*ff)();//A
    (b.*ff)();//B
}
class A{
public:
    int fun(){
        cout<<"A";
        return 0;
    }
};

class B:public A{
public:
    int fun() {
        cout<<"B";
        return 0;
    }
};

typedef int(A::*f)();

int main(int _argc,char* _argv[]){
    f ff=f(&B::fun);
    A a{};
    B b{};
    (a.*ff)();//B
    (b.*ff)();//B
}

you can not cast non virtual function pointer

class Foo{
public:
  int f(char* c=0){
    std::cout<<"Foo::f()"<<std::endl;
    return 1;
  }
};
 
class Bar{
public:
  void b(int i=0){
    std::cout<<"Bar::b()"<<std::endl;
  }
};
 
class FooDerived:public Foo{
public:
  int f(char* c=0){
    std::cout<<"FooDerived::f()"<<std::endl;
    return 1;
  }
};
 
int main(int argc, char* argv[]){
  typedef  int (Foo::*FPTR) (char*);
  typedef  void (Bar::*BPTR) (int);
  typedef  int (FooDerived::*FDPTR) (char*);
 
  FPTR fptr = &Foo::f;
  BPTR bptr = &Bar::b;
  FDPTR fdptr = &FooDerived::f;
 
  //Bptr = static_cast<void (Bar::*) (int)> (fptr); //error
  fdptr = static_cast<int (Foo::*) (char*)> (fptr); //OK: contravariance
 
  Bar obj;
  ( obj.*(BPTR) fptr )(1);//call: Foo::f()
}
Output:
Foo::f()

you can cast virtual function pointer

class Foo{
public:
  virtual int f(char* c=0){
    std::cout<<"Foo::f()"<<std::endl;
    return 1;
  }
};
 
class Bar{
public:
  virtual void b(int i=0){
    std::cout<<"Bar::b()"<<std::endl;
  }
};
 
class FooDerived:public Foo{
public:
  int f(char* c=0){
    std::cout<<"FooDerived::f()"<<std::endl;
    return 1;
  }
};
 
int main(int argc, char* argv[]){
  typedef  int (Foo::*FPTR) (char*);
  typedef  void (Bar::*BPTR) (int);
  FPTR fptr=&Foo::f;
  BPTR bptr=&Bar::b;
 
  FooDerived objDer;
  (objDer.*fptr)(0);//call: FooDerived::f(), not Foo::f()
 
  Bar obj;
  ( obj.*(BPTR) fptr )(1);//call: Bar::b() , not Foo::f()
}
Output:
FooDerived::f()
Bar::b()
class A{
public:
    void fun(){
        cout<<"A";
    }
};
class B:public A{
public:
    void fun(){
        cout<<"B";
    }
};
int main(int _argc,char* _argv[]){
    typedef void (A::*f)();
    f f1=(f)&B::fun;
    B b;
    (b.*f1)();// if B did not inherit A (b.*(void (B::*)())f1)();
}

generic function pointer

template<class T>
void fun(void(T::*f)(int)){
    T t;
    (t.*f)(12);
}

class A{
    public:
        void fun(int i){
            cout<<i;
        }
    };

int main(int argc,char* argv[]){
    fun(&A::fun);
    return 0;
}
template<int i,typename T>
 int iter(T t){
     return i-1;
 }

 template<typename T>
 struct A{
     T t;
 };

 template<typename T>
 using fun= int(*)(T t);

 template <typename T>
 using attr=T A<T>::*;


int main(int argc, char *argv[])
{
    QCoreApplication a(argc,argv);
    fun<int> f=iter<2,int>;
    attr<int> at=&A<int>::t;

    return a.exec();
}

lambda expression

[ captures ] ( params ) -> ret { body }
[ captures ] ( params ) { body }
[ captures ] { body }

[&]{};          // OK: by-reference capture default
[&, i]{};       // OK: by-reference capture, except i is captured by copy
[&, &i] {};     // Error: by-reference capture when by-reference is the default
[&, this] {};   // OK, equivalent to [&]
[&, this, i]{}; // OK, equivalent to [&, i]
[=]{};          // OK: by-copy capture default
[=, &i]{};      // OK: by-copy capture, except i is captured by reference
[=, *this]{};   // until C++17: Error: invalid syntax
                    // since c++17: OK: captures the enclosing S2 by copy
[=, this] {};   // until C++20: Error: this when = is the default
                    // since C++20: OK, same as [=]
auto fun=[](int i)->int {return i;};
std::function<int(int)> fun2=fun;
int(*fun3)(int)=fun;
cout<<fun2(4);
class S {
  int x = 0;
  void f() {
    int i = 0;
//  auto l1 = [i, x]{ use(i, x); };    // error: x is not a variable
    auto l2 = [i, x=x]{ use(i, x); };  // OK, copy capture
    i = 1; x = 1; l2(); // calls use(0,0)
    auto l3 = [i, &x=x]{ use(i, x); }; // OK, reference capture
    i = 2; x = 2; l3(); // calls use(1,2)
  }
};
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
 
int main()
{
    std::vector<int> c = {1, 2, 3, 4, 5, 6, 7};
    int x = 5;
    c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; }), c.end());
 
    std::cout << "c: ";
    std::for_each(c.begin(), c.end(), [](int i){ std::cout << i << ' '; });
    std::cout << '\n';
 
    // the type of a closure cannot be named, but can be inferred with auto
    // since C++14, lambda could own default arguments
    auto func1 = [](int i = 6) { return i + 4; };
    std::cout << "func1: " << func1() << '\n';
 
    // like all callable objects, closures can be captured in std::function
    // (this may incur unnecessary overhead)
    std::function<int(int)> func2 = [](int i) { return i + 4; };
    std::cout << "func2: " << func2(6) << '\n';
}

Function Declaration

Return type deduction
int x = 1;
auto f() { return x; }        // return type is int
const auto& f() { return x; } // return type is const int&
auto f(bool val)
{
    if (val) return 123; // deduces return type int
    else return 3.14f;   // error: deduces return type float
}
auto f() {}              // returns void
auto g() { return f(); } // returns void
auto* x() {}             // error: cannot deduce auto* from void
struct F
{
    virtual auto f() { return 2; } // error virtual function cannot return type deduction
};

declarations examples

int a = 1, *p = NULL, f(), (*pf)(double);
// decl-specifier-seq is int
// declarator f() declares (but doesn't define)
//                a function taking no arguments and returning int
 
struct S
{
    virtual int f(char) const, g(int) &&; // declares two non-static member functions
    virtual int f(char), x; // compile-time error: virtual (in decl-specifier-seq)
                            // is only allowed in declarations of non-static
                            // member functions
};
int f(int a, int *p, int (*(*x)(double))[3]);
int f(int a = 7, int *p = nullptr, int (*(*x)(double))[3] = nullptr);
int f(int, int *, int (*(*)(double))[3]);
int f(int = 7, int * = nullptr, int (*(*)(double))[3] = nullptr);

Default arguments

int fun0(){
    std::vector<int> v{1,2,3,4};
    return v.size();
}
void fun(int i=fun0()){

}

Argument-dependent lookup

int main()
{
    std::cout << "Test\n"; // There is no operator<< in global namespace, but ADL
                           // examines std namespace because the left argument is in
                           // std and finds std::operator<<(std::ostream&, const char*)
    operator<<(std::cout, "Test\n"); // same, using function call notation
 
    // however,
    std::cout << endl; // Error: 'endl' is not declared in this namespace.
                       // This is not a function call to endl(), so ADL does not apply
 
    endl(std::cout); // OK: this is a function call: ADL examines std namespace
                     // because the argument of endl is in std, and finds std::endl
 
    (endl)(std::cout); // Error: 'endl' is not declared in this namespace.
                       // The sub-expression (endl) is not a function call expression
}
using std::swap;
swap(obj1, obj2);
namespace A {
      struct X;
      struct Y;
      void f(int);
      void g(X);
}
 
namespace B {
    void f(int i) {
        f(i);   // calls B::f (endless recursion)
    }
    void g(A::X x) {
        g(x);   // Error: ambiguous between B::g (ordinary lookup)
                //        and A::g (argument-dependent lookup)
    }
    void h(A::Y y) {
        h(y);   // calls B::h (endless recursion): ADL examines the A namespace
                // but finds no A::h, so only B::h from ordinary lookup is used
    }
}

Overload Resolution

struct B { void f(int); };
struct A { operator B&(); };
A a;
a.B::f(1); // Error: user-defined conversions cannot be applied
           // to the implicit object parameter
static_cast<B&>(a).f(1); // OK
int f1(int);
int f2(float);
struct A {
    using fp1 = int(*)(int);
    operator fp1() { return f1; } // conversion function to pointer to function
    using fp2 = int(*)(float);
    operator fp2() { return f2; } // conversion function to pointer to function
} a;
int i = a(1); // calls f1 via pointer returned from conversion function
struct A {
    operator int(); // user-defined conversion
};
A operator+(const A&, const A&); // non-member user-defined operator
void m()
{
    A a, b;
    a + b; // member-candidates: none
           // non-member candidates: operator+(a,b)
           // built-in candidates: int(a) + int(b)
           // overload resolution chooses operator+(a,b)
}
struct Y { operator int*(); };  // Y is convertible to int*
int *a = Y() + 100.0; // error: no operator+ between pointer and double

Viable functions

struct A { A(int); };
struct B { B(A); };
B b{ {0} }; // list-init of B
// candidates: B(const B&), B(B&&), B(A)
// {0} -> B&& not viable: would have to call B(A)
// {0} -> const B&: not viable: would have to bind to rvalue, would have to call B(A)
// {0} -> A viable. Calls A(int): user-defined conversion to A is not banned
template<class T> struct A {
    using value_type = T;
    A(value_type);                  // #1
    A(const A&);                    // #2
    A(T, T, int);                   // #3
    template<class U> A(int, T, U); // #4
};                                 
A x (1, 2, 3);  // uses #3, generated from a non-template constructor
A a (42); // uses #6 to deduce A<int> and #1 to initialize
A b = a;  // uses #5 to deduce A<int> and #2 to initialize
A b2 = a;  // uses #7 to deduce A<A<int>> and #1 to initialize
void Fcn(const int*, short); // overload #1
void Fcn(int*, int); // overload #2
int i;
short s = 0;
void f() 
{
    Fcn(&i, 1L);  // 1st argument: &i -> int* is better than &i -> const int*
                  // 2nd argument: 1L -> short and 1L -> int are equivalent
                  // calls Fcn(int*, int)
 
    Fcn(&i,'c');  // 1st argument: &i -> int* is better than &i -> const int*
                  // 2nd argument: 'c' -> int is better than 'c' -> short
                  // calls Fcn(int*, int)
 
    Fcn(&i, s);   // 1st argument: &i -> int* is better than &i -> const int*
                  // 2nd argument: s -> short is better than s -> int
                  // no winner, compilation error
}

Ranking of implicit conversion sequences

struct Base {};
struct Derived : Base {} d;
int f(Base&);    // overload #1
int f(Derived&); // overload #2
int i = f(d); // d -> Derived& has rank Exact Match
              // d -> Base& has rank Conversion
              // calls f(Derived&)
int i;
int f1();
int g(const int&);  // overload #1
int g(const int&&); // overload #2
int j = g(i);    // lvalue int -> const int& is the only valid conversion
int k = g(f1()); // rvalue int -> const int&& better than rvalue int -> const int&
int f(void(&)());  // overload #1
int f(void(&&)()); // overload #2
void g();
int i1 = f(g);     // calls #1
int f(const int &); // overload #1
int f(int &);       // overload #2 (both references)
int g(const int &); // overload #1
int g(int);         // overload #2
int i;
int j = f(i); // lvalue i -> int& is better than lvalue int -> const int&
              // calls f(int&)
int k = g(i); // lvalue i -> const int& ranks Exact Match
              // lvalue i -> rvalue int ranks Exact Match
              // ambiguous overload: compilation error
int f(const int*);
int f(int*);
int i;
int j = f(&i); // &i -> int* is better than &i -> const int*, calls f(int*)
struct A {
    operator short(); // user-defined conversion function
} a;
int f(int);   // overload #1
int f(float); // overload #2
int i = f(a); // A -> short, followed by short -> int (rank Promotion)
              // A -> short, followed by short -> float (rank Conversion)
              // calls f(int)

Implicit conversion sequence in list-initialization

void f1(int);                                 // #1
void f1(std::initializer_list<long>);         // #2
void g1() { f1({42}); }                       // chooses #2
 
void f2(std::pair<const char*, const char*>); // #3
void f2(std::initializer_list<std::string>);  // #4
void g2() { f2({"foo","bar"}); }              // chooses #4
void f(int    (&&)[] );    // overload #1
void f(double (&&)[] );    // overload #2
void f(int    (&&)[2]);    // overload #3
 
f({1});          // #1: Better than #2 due to conversion, better than #3 due to bounds
f({1.0});        // #2: double -> double is better than double -> int
f({1.0, 2.0});   // #2: double -> double is better than double -> int
f({1, 2});       // #3: -> int[2] is better than -> int[], 
                 //     and int -> int is better than int -> double
struct A { int x, y; };
struct B { int y, x; };
 
void f(A a, int); // #1
void f(B b, ...); // #2
void g(A a); // #3
void g(B b); // #4
 
void h() 
{
    f({.x = 1, .y = 2}, 0); // OK; calls #1
    f({.y = 2, .x = 1}, 0); // error: selects #1, initialization of a fails
                            // due to non-matching member order
    g({.x = 1, .y = 2}); // error: ambiguous between #3 and #4
}
struct A { A(std::initializer_list<int>); };
void f(A);
struct B { B(int, double); };
void g(B);
g({'a','b'});  // calls g(B(int,double)), user-defined conversion
// g({1.0, 1,0}); // error: double->int is narrowing, not allowed in list-init
void f(B);
// f({'a','b'}); // f(A) and f(B) both user-defined conversions
struct A { int m1; double m2;};
void f(A);
f({'a','b'});  // calls f(A(int,double)), user-defined conversion

operator overloading

assignmentincrement
decrement
arithmeticlogicalcomparisonmember
access
other
a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b
++a
–a
a++
a–
+a
-a
a + b
a – b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b
!a
a && b
a || b
a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b
a[b]
*a
&a
a->b
a.b
a->*b
a.*b
a(…)
a, b
? :

static_cast converts one type to another related type
dynamic_cast converts within inheritance hierarchies
const_cast adds or removes cv qualifiers
reinterpret_cast converts type to unrelated type
C-style cast converts one type to another by a mix of static_castconst_cast, and reinterpret_cast
new creates objects with dynamic storage duration
delete destructs objects previously created by the new expression and releases obtained memory area
sizeof queries the size of a type
sizeof… queries the size of a parameter pack (since C++11)
typeid queries the type information of a type
noexcept checks if an expression can throw an exception (since C++11)
alignof queries alignment requirements of a type (since C++11)

(since C++20) && || ++ — , ->* -> ( ) [ ]

std::string str = "Hello, ";
str.operator+=("world");                       // same as str += "world";
operator<<(operator<<(std::cout, str) , '\n'); // same as std::cout << str << '\n';
                                               // (since C++17) except for sequencing

assignment operator

T& operator=(const T& other) // copy assignment
{
    if (this != &other) { // self-assignment check expected
        if (other.size != size) {         // storage cannot be reused
            delete[] mArray;              // destroy storage in this
            size = 0;
            mArray = nullptr;             // preserve invariants in case next line throws
            mArray = new int[other.size]; // create storage in this
            size = other.size;
        } 
        std::copy(other.mArray, other.mArray + other.size, mArray);
    }
    return *this;
}
T& operator=(T&& other) noexcept // move assignment
{
    if(this != &other) { // no-op on self-move-assignment (delete[]/size=0 also ok)
        delete[] mArray;                               // delete this storage
        mArray = std::exchange(other.mArray, nullptr); // leave moved-from in valid state
        size = std::exchange(other.size, 0);
    }
    return *this;
}
T& T::operator=(T arg) noexcept // copy/move constructor is called to construct arg
{
    std::swap(size, arg.size); // resources are exchanged between *this and arg
    std::swap(mArray, arg.mArray);
    return *this;
}

example

class Fraction
{
    int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
    int n, d;
public:
    Fraction(int n, int d = 1) : n(n/gcd(n, d)), d(d/gcd(n, d)) { }
    int num() const { return n; }
    int den() const { return d; }
    Fraction& operator*=(const Fraction& rhs)
    {
        int new_n = n * rhs.n/gcd(n * rhs.n, d * rhs.d);
        d = d * rhs.d/gcd(n * rhs.n, d * rhs.d);
        n = new_n;
        return *this;
    }
};
std::ostream& operator<<(std::ostream& out, const Fraction& f)
{
   return out << f.num() << '/' << f.den() ;
}
bool operator==(const Fraction& lhs, const Fraction& rhs)
{
    return lhs.num() == rhs.num() && lhs.den() == rhs.den();
}
bool operator!=(const Fraction& lhs, const Fraction& rhs)
{
    return !(lhs == rhs);
}
Fraction operator*(Fraction lhs, const Fraction& rhs)
{
    return lhs *= rhs;
}
 
int main()
{
   Fraction f1(3, 8), f2(1, 2), f3(10, 2);
   std::cout << f1 << " * " << f2 << " = " << f1 * f2 << '\n'
             << f2 << " * " << f3 << " = " << f2 * f3 << '\n'
             <<  2 << " * " << f1 << " = " <<  2 * f1 << '\n';
}

Address of an overloaded function

int f(int) { return 1; }
int f(double) { return 2; }
 
void g( int(&f1)(int), int(*f2)(double) ) {}
 
template< int(*F)(int) >
struct Templ {};
 
struct Foo {
    int mf(int) { return 3; }
    int mf(double) { return 4; }
};
 
struct Emp {
    void operator<<(int (*)(double)) {}
};
 
int main()
{
    // 1. initialization
    int (*pf)(double) = f; // selects int f(double)
    int (&rf)(int) = f; // selects int f(int)
    int (Foo::*mpf)(int) = &Foo::mf; // selects int mf(int)
 
    // 2. assignment
    pf = nullptr;
    pf = &f; // selects int f(double)
 
    // 3. function argument
    g(f, f); // selects int f(int) for the 1st argument
             // and int f(double) for the second
 
    // 4. user-defined operator
    Emp{} << f; //selects int f(double)
 
    // 5. return value
    auto foo = []() -> int (*)(int) {
        return f; // selects int f(int)
    };
 
    // 6. cast
    auto p = static_cast<int(*)(int)>(f); // selects int f(int)
 
    // 7. template argument
    Templ<f> t;  // selects int f(int)
}

Declarations in c++

Enum

enum name { enumerator = constexpr , enumerator = constexpr , … }
enum name : type { enumerator = constexpr , enumerator = constexpr , … }
enum name : type ;
enum A{
    One=0,
    Two=1,
    Three=3
};
class AA{
public:
    enum A{
        One=0,
        Two=1,
        Three=3
    };
};
int main(int _argc,char* _argv[]){
    int l=::A::One;
    l=::One;
    ::A a=(::A)1;
    AA::A aa=AA::One;
    aa=AA::A::One;
}
enum num : char { one = '0' };
std::cout << num::one; // '0', not 48
enum Foo { a, b, c = 10, d, e = 1, f, g = f + c };
//a = 0, b = 1, c = 10, d = 11, e = 1, f = 2, g = 12

Array

int a[2];            // array of 2 int
int* p1 = a;         // a decays to a pointer to the first element of a
 
int b[2][3];         // array of 2 arrays of 3 int
// int** p2 = b;     // error: b does not decay to int**
int (*p2)[3] = b;    // b decays to a pointer to the first 3-element row of b
 
int c[2][3][4];      // array of 2 arrays of 3 arrays of 4 int
// int*** p3 = c;    // error: c does not decay to int***
int (*p3)[3][4] = c; // c decays to a pointer to the first 3 × 4-element plane of c
int l[]{1,2,3,4,5,6,7};//or = {1,2,3,4,5,6,7};
int m=*(l+4);
//l++ ++l errors
int* k=new int[5]{1,2,3,4,5};
void g(int (&a)[3])
{
    std::cout << a[0] << '\n';
}
 
void f(int* p)
{
    std::cout << *p << '\n';
}
 
int main()
{
    int a[3] = {1, 2, 3};
    int* p = a;
 
    std::cout << sizeof a << '\n'  // prints size of array
              << sizeof p << '\n'; // prints size of a pointer
 
    // where arrays are acceptable, but pointers aren't, only arrays may be used
    g(a); // okay: function takes an array by reference
//  g(p); // error
 
    for(int n: a)              // okay: arrays can be used in range-for loops
        std::cout << n << ' '; // prints elements of the array
//  for(int n: p)              // error
//      std::cout << n << ' ';
 
    // where pointers are acceptable, but arrays aren't, both may be used:
    f(a); // okay: function takes a pointer
    f(p); // okay: function takes a pointer
 
    std::cout << *a << '\n' // prints the first element
              << *p << '\n' // same
              << *(a + 1) << ' ' << a[1] << '\n'  // prints the second element
              << *(p + 1) << ' ' << p[1] << '\n'; // same
}

Namespace

namespace Q {
  namespace V { // original-namespace-definition for V
    void f(); // declaration of Q::V::f
  }
  void V::f() {} // OK
  void V::g() {} // Error: g() is not yet a member of V
  namespace V { // extension-namespace-definition for V
    void g(); // declaration of Q::V::g
  }
}
namespace R { // not a enclosing namespace for Q
   void Q::V::g() {} // Error: cannot define Q::V::g inside R
}
void Q::V::g() {} // OK: global namespace encloses Q
namespace D {
   int d1;
   void f(char);
}
using namespace D; // introduces D::d1, D::f, D::d2, D::f,
                   //  E::e, and E::f into global namespace!
 
int d1; // OK: no conflict with D::d1 when declaring
namespace E {
    int e;
    void f(int);
}
namespace D { // namespace extension
    int d2;
    using namespace E; // transitive using-directive
    void f(int);
}
void f() {
    d1++; // error: ambiguous ::d1 or D::d1?
    ::d1++; // OK
    D::d1++; // OK
    d2++; // OK, d2 is D::d2
    e++; // OK: e is E::e due to transitive using
    f(1); // error: ambiguous: D::f(int) or E::f(int)?
    f('a'); // OK: the only f(char) is D::f(char)
}
namespace vec {
 
    template< typename T >
    class vector {
        // ...
    };
 
} // of vec
 
int main()
{
    std::vector<int> v1; // Standard vector.
    vec::vector<int> v2; // User defined vector.
 
    v1 = v2; // Error: v1 and v2 are different object's type.
 
    {
        using namespace std;
        vector<int> v3; // Same as std::vector
        v1 = v3; // OK
    }
 
    {
        using vec::vector;
        vector<int> v4; // Same as vec::vector
        v2 = v4; // OK
    }
 
    return 0;
}
namespace foo {
    namespace bar {
         namespace baz {
             int qux = 42;
         }
    }
}
 
namespace fbz = foo::bar::baz;
 
int main()
{
    std::cout << fbz::qux << '\n';
}

Reference declaration

int& a[3]; // error
int&* p;   // error
int& &r;   // error

typedef int&  lref;
typedef int&& rref;
int n;
lref&  r1 = n; // type of r1 is int&
lref&& r2 = n; // type of r2 is int&
rref&  r3 = n; // type of r3 is int&
rref&& r4 = 1; // type of r4 is int&&
void f(int& x) {
    std::cout << "lvalue reference overload f(" << x << ")\n";
}
 
void f(const int& x) {
    std::cout << "lvalue reference to const overload f(" << x << ")\n";
}
 
void f(int&& x) {
    std::cout << "rvalue reference overload f(" << x << ")\n";
}
 
int main() {
    int i = 1;
    const int ci = 2;
    f(i);  // calls f(int&)
    f(ci); // calls f(const int&)
    f(3);  // calls f(int&&)
           // would call f(const int&) if f(int&&) overload wasn't provided
    f(std::move(i)); // calls f(int&&)
 
    // rvalue reference variables are lvalues when used in expressions
    int&& x = 1;
    f(x);            // calls f(int& x)
    f(std::move(x)); // calls f(int&& x)
}

forwarding

template<class T>
int f(T&& x) {                    // x is a forwarding reference
    return g(std::forward<T>(x)); // and so can be forwarded
}
 
int main() {
    int i;
    f(i); // argument is lvalue, calls f<int&>(int&), std::forward<int&>(x) is lvalue
    f(0); // argument is rvalue, calls f<int>(int&&), std::forward<int>(x) is rvalue
}
 
template<class T>
int g(const T&& x); // x is not a forwarding reference: const T is not cv-unqualified
 
template<class T> struct A {
    template<class U>
    A(T&& x, U&& y, int* p); // x is not a forwarding reference: T is not a
                             // type template parameter of the constructor,
                             // but y is a forwarding reference
};

Pointer

pointer to object

struct C {
   int x, y;
} c;
 
int* px = &c.x;   // value of px is "pointer to c.x"
int* pxe= px + 1; // value of pxe is "pointer past the end of c.x"
int* py = &c.y;   // value of py is "pointer to c.y"
 
assert(pxe == py); // == tests if two pointers represent the same address
                   // may or may not fire
 
*pxe = 1; // undefined behavior even if the assertion does not fire
int n;
int* np = &n; // pointer to int
int* const* npp = &np; // non-const pointer to const pointer to non-const int
 
int a[2];
int (*ap)[2] = &a; // pointer to array of int
 
struct S { int n; };
S s = {1};
int* sp = &s.n; // pointer to the int that is a member of s
int n;
int* p = &n;     // pointer to n
int& r = *p;     // reference is bound to the lvalue expression that identifies n
r = 7;           // stores the int 7 in n
std::cout << *p; // lvalue-to-rvalue implicit conversion reads the value from n
int a[2];
int* p1 = a; // pointer to the first element a[0] (an int) of the array a
 
int b[6][3][8];
int (*p2)[3][8] = b; // pointer to the first element b[0] of the array b,
                     // which is an array of 3 arrays of 8 ints

struct Base {};
struct Derived : Base {};
 
Derived d;
Base* p = &d;

const pointer

Syntaxmeaning
const T*pointer to constant object
T const*pointer to constant object
T* constconstant pointer to object
const T* constconstant pointer to constant object
T const* constconstant pointer to constant object
const int* const i=new int ;
const int* const* ii=&i;//non-const pointer to const pointer to const object
const int n1=12;
const int* n2=&n1;//int* is error 

pointer to void

int n = 1;
int* p1 = &n;
void* pv = p1;
int* p2 = static_cast<int*>(pv);
std::cout << *p2 << '\n'; // prints 1

pointer to functions

int (* f)()f is a pointer to a function with prototype int func().
int (* f())()f is a function taking no inputs and returning a pointer to a function with prototype int func().
int * f()f is a function returning a pointer-to-int.
int (* a[])()a is an array of pointers to functions each with prototype int func().
int (* f())[]f is a function returning a pointer to an array.
int (f[])()Not allowed. Can’t have an array of functions.
int * const *(*g)(float)g is pointer to a function with prototype int * const * func(float) where its return value int * const * is a pointer to a read-only pointer-to-int.
int f();
int (*p)() = f;  // pointer p is pointing to f
int (&r)() = *p; // the lvalue that identifies f is bound to a reference
r();             // function f invoked through lvalue reference
(*p)();          // function f invoked through the function lvalue
p();  

Pointers to data members

struct C { int m; };
 
int main()
{
    int C::* p = &C::m;          // pointer to data member m of class C
    C c = {7};
    std::cout << c.*p << '\n';   // prints 7
    C* cp = &c;
    cp->m = 10;
    std::cout << cp->*p << '\n'; // prints 10
}
struct Base { int m; };
struct Derived : Base {};
 
int main()
{
    int Base::* bp = &Base::m;
    int Derived::* dp = bp;
    Derived d;
    d.m = 1;
    std::cout << d.*dp << ' ' << d.*bp << '\n'; // prints 1 1
}
struct A
{
    int m;
    // const pointer to non-const member
    int A::* const p;
};
 
int main()
{
    // non-const pointer to data member which is a const pointer to non-const member
    int A::* const A::* p1 = &A::p;
 
    const A a = {1, &A::m};
    std::cout << a.*(a.*p1) << '\n'; // prints 1
 
    // regular non-const pointer to a const pointer-to-member
    int A::* const* p2 = &a.p;
    std::cout << a.**p2 << '\n'; // prints 1
}

Pointers to function members

struct Base
{
    void f(int n) { std::cout << n << '\n'; }
};
struct Derived : Base {};
 
int main()
{
    void (Base::* bp)(int) = &Base::f;
    void (Derived::* dp)(int) = bp;
    Derived d;
    (d.*dp)(1);
    (d.*bp)(2);
}
struct Base {};
struct Derived : Base
{
    void f(int n) { std::cout << n << '\n'; }
};
 
int main()
{
    void (Derived::* dp)(int) = &Derived::f;
    void (Base::* bp)(int) = static_cast<void (Base::*)(int)>(dp);
 
    Derived d;
    (d.*bp)(1); // okay: prints 1
 
    Base b;
    (b.*bp)(2); // undefined behavior
}

null pointer

To initialize a pointer to null or to assign the null value to an existing pointer, the null pointer literal nullptr, the null pointer constant NULL, or the implicit conversion from the integer value ​0​ may be used.

const and volatile and Mutable

int main()
{
    int n1 = 0;           // non-const object
    const int n2 = 0;     // const object
    int const n3 = 0;     // const object (same as n2)
    volatile int n4 = 0;  // volatile object
    const struct
    {
        int n1;
        mutable int n2;
    } x = {0, 0};      // const object with mutable member
 
    n1 = 1; // ok, modifiable object
//  n2 = 2; // error: non-modifiable object
    n4 = 3; // ok, treated as a side-effect
//  x.n1 = 4; // error: member of a const object is const
    x.n2 = 4; // ok, mutable member of a const object isn't const
 
    const int& r1 = n1; // reference to const bound to non-const object
//  r1 = 2; // error: attempt to modify through reference to const
    const_cast<int&>(r1) = 2; // ok, modifies non-const object n1
 
    const int& r2 = n2; // reference to const bound to const object
//  r2 = 2; // error: attempt to modify through reference to const
//  const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object n2
}
class Test { 
public: 
  int x; 
  mutable int y; 
  Test() { x = 4; y = 10; } 
}; 
int main() 
{ 
    const Test t1; 
    t1.y = 20; 
    cout << t1.y; 
    return 0; 
}
class Customer 
{ 
    char name[25]; 
    mutable char placedorder[50]; 
    int tableno; 
    mutable int bill; 
public: 
    Customer(char* s, char* m, int a, int p) 
    { 
        strcpy(name, s); 
        strcpy(placedorder, m); 
        tableno = a; 
        bill = p; 
    } 
    void changePlacedOrder(char* p) const
    { 
        strcpy(placedorder, p); 
    } 
    void changeBill(int s) const
    { 
        bill = s; 
    } 
    void display() const
    { 
        cout << "Customer name is: " << name << endl; 
        cout << "Food ordered by customer is: " << placedorder << endl; 
        cout << "table no is: " << tableno << endl; 
        cout << "Total payable amount: " << bill << endl; 
    } 
}; 

constexpr specifier

The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.

#include <iostream>
#include <stdexcept>
 
// C++11 constexpr functions use recursion rather than iteration
// (C++14 constexpr functions may use local variables and loops)
constexpr int factorial(int n)
{
    return n <= 1 ? 1 : (n * factorial(n - 1));
}
 
// literal class
class conststr {
    const char* p;
    std::size_t sz;
public:
    template<std::size_t N>
    constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}
 
    // constexpr functions signal errors by throwing exceptions
    // in C++11, they must do so from the conditional operator ?:
    constexpr char operator[](std::size_t n) const
    {
        return n < sz ? p[n] : throw std::out_of_range("");
    }
    constexpr std::size_t size() const { return sz; }
};
 
// C++11 constexpr functions had to put everything in a single return statement
// (C++14 doesn't have that requirement)
constexpr std::size_t countlower(conststr s, std::size_t n = 0,
                                             std::size_t c = 0)
{
    return n == s.size() ? c :
           'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) :
                                       countlower(s, n + 1, c);
}
 
// output function that requires a compile-time constant, for testing
template<int n>
struct constN
{
    constN() { std::cout << n << '\n'; }
};
 
int main()
{
    std::cout << "4! = " ;
    constN<factorial(4)> out1; // computed at compile time
 
    volatile int k = 8; // disallow optimization using volatile
    std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time
 
    std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
    constN<countlower("Hello, world!")> out2; // implicitly converted to conststr
}

decltype 

struct A { double x; };
const A* a;
 
decltype(a->x) y;       // type of y is double (declared type)
decltype((a->x)) z = y; // type of z is const double& (lvalue expression)
 
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // return type depends on template parameters
                                      // return type can be deduced since C++14
{
    return t+u;
}
 
int main() 
{
    int i = 33;
    decltype(i) j = i * 2;
 
    std::cout << "i = " << i << ", "
              << "j = " << j << '\n';
 
    auto f = [](int a, int b) -> int
    {
        return a * b;
    };
 
    decltype(f) g = f; // the type of a lambda function is unique and unnamed
    i = f(2, 2);
    j = g(3, 3);
 
    std::cout << "i = " << i << ", "
              << "j = " << j << '\n';
}

auto

#include <iostream>
#include <utility>

template<class T, class U>
auto add(T t, U u) { return t + u; } // the return type is the type of operator+(T, U)

// perfect forwarding of a function call must use decltype(auto)
// in case the function it calls returns by reference
template<class F, class... Args>
decltype(auto) PerfectForward(F fun, Args&&... args)
{
    return fun(std::forward<Args>(args)...);
}

template<auto n> // C++17 auto parameter declaration
auto f() -> std::pair<decltype(n), decltype(n)> // auto can't deduce from brace-init-list
{
    return {n, n};
}

int main()
{
    auto a = 1 + 2;            // type of a is int
    auto b = add(1, 1.2);      // type of b is double
    static_assert(std::is_same_v<decltype(a), int>);
    static_assert(std::is_same_v<decltype(b), double>);

    auto c0 = a;             // type of c0 is int, holding a copy of a
    decltype(auto) c1 = a;   // type of c1 is int, holding a copy of a
    decltype(auto) c2 = (a); // type of c2 is int&, an alias of a
    std::cout << "a, before modification through c2 = " << a << '\n';
    ++c2;
    std::cout << "a, after modification through c2 = " << a << '\n';

    auto [v, w] = f<0>(); //structured binding declaration
    std::cout<<v<<w;

    auto d = {1, 2}; // OK: type of d is std::initializer_list<int>
    auto n = {5};    // OK: type of n is std::initializer_list<int>
//  auto e{1, 2};    // Error as of C++17, std::initializer_list<int> before
    auto m{5};       // OK: type of m is int as of C++17, initializer_list<int> before
//  decltype(auto) z = { 1, 2 } // Error: {1, 2} is not an expression

    // auto is commonly used for unnamed types such as the types of lambda expressions
    auto lambda = [](int x) { return x + 3; };

//  auto int x; // valid C++98, error as of C++11
//  auto x;     // valid C, error in C++
}

decltype(auto)

 in generic code you want to be able to perfectly forward a return type without knowing whether you are dealing with a reference or a value. decltype(auto) gives you that ability:

int i;
int&& f();
auto x3a = i;                  // decltype(x3a) is int
decltype(auto) x3d = i;        // decltype(x3d) is int
auto x4a = (i);                // decltype(x4a) is int
decltype(auto) x4d = (i);      // decltype(x4d) is int&
auto x5a = f();                // decltype(x5a) is int
decltype(auto) x5d = f();      // decltype(x5d) is int&&
auto x6a = { 1, 2 };           // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto *x7a = &i;                // decltype(x7a) is int*
decltype(auto)*x7d = &i;       // error, declared type is not plain decltype(auto)
template<class Fun, class... Args>
decltype(auto) Example(Fun fun, Args&&... args) 
{ 
    return fun(std::forward<Args>(args)...); 
}

Delaying return type deduction in recursive templates

template<int i> 
struct Int {};

constexpr auto iter(Int<0>) -> Int<0>;

template<int i>
constexpr auto iter(Int<i>) -> decltype(auto) 
{ return iter(Int<i-1>{}); }

int main() { decltype(iter(Int<10>{})) a; }

Elaborated type

enum A { A_START = 0 };

void A(enum A a) {}

int main() {
   enum A a;
   A( a );
}
template <typename T>
struct Node {
    struct Node* Next; // OK: lookup of Node finds the injected-class-name
    struct Data* Data; // OK: declares type Data at global scope
                       // and also declares the data member Data
    friend class ::List; // error: cannot introduce a qualified name
    enum Kind* kind; // error: cannot introduce an enum
};
 
Data* p; // OK: struct Data has been declared

Supernode

The two nonreference nodes form supernode if the voltage source (dependent or independent) is connected between two nonreference nodes. As shown below in Figure 1, 1 V voltage source is connected between nodes 1 and 2, so node 1 and node 2 forms supernode.

supernode

Procedure (steps) for applying Nodal Analysis: –

  1. Identify the total number of nodes.
  2. One node selected as reference node and it is assigned to have ground (zero) potential and the remaining nodes called as nonreference node and we assign voltage designations to nonreference nodes. And at last check for supernode.
  3. Develop the KCL equations for each nonreference node.
  4. Solve the equations to find the unknown node voltages.

Note:- Apply both KCL and KVL to determine the node voltages.

Example

Example 1.  For the given network, find nodal voltages V1 and V2.

supernode

Solution:

As shown in the above Figure, given in the question, 1 V voltage source is connected between nodes 1 and 2, so node 1 and node 2 forms supernode. Thus this problem is based on supernode.

Step 1: – The total number of nodes is 3.

Step 2: – Node 0 is selected as reference node and it is assigned to have ground (zero) potential. The remaining node 1 and node 2 are considered as non-reference node shown in Figure 1. Here, node 1 and node 2 forms supernode.

supernode

Step 3 and Step 4: – Apply both KCL and KVL to determine the node voltages.

Apply KCL to supernode as shown in Figure 2,

2+(V1–0)/1+(V2–0)/1+(V2–2)/1=0

V1+2V2=0   ……(1)

Apply KVL to the loop having current I as shown in Figure 2,

V1–V2=1    ……(2)

Put Eq.(2) in Eq.(1), we get

3V2+1=0

V2=–1/3 V

From Eq.(1), V1+2V2=0

V1+2(–1/3)=0

V1=2/3 V.

supernode

Kirchhoffs Circuit Law

Kirchhoffs First Law – The Current Law, (KCL)

Kirchhoffs Current Law or KCL, states that the “total current or charge entering a junction or node is exactly equal to the charge leaving the node as it has no other place to go except to leave, as no charge is lost within the node“. In other words the algebraic sum of ALL the currents entering and leaving a node must be equal to zero, I(exiting) + I(entering) = 0. This idea by Kirchhoff is commonly known as the Conservation of Charge.

Kirchhoffs Current Law

kirchhoffs current law

Here, the three currents entering the node, I1, I2, I3 are all positive in value and the two currents leaving the node, I4 and I5 are negative in value. Then this means we can also rewrite the equation as;

I1 + I2 + I3 – I4 – I5 = 0

The term Node in an electrical circuit generally refers to a connection or junction of two or more current carrying paths or elements such as cables and components. Also for current to flow either in or out of a node a closed circuit path must exist. We can use Kirchhoff’s current law when analysing parallel circuits.

Kirchhoffs Second Law – The Voltage Law, (KVL)

Kirchhoffs Voltage Law or KVL, states that “in any closed loop network, the total voltage around the loop is equal to the sum of all the voltage drops within the same loop” which is also equal to zero. In other words the algebraic sum of all voltages within the loop must be equal to zero. This idea by Kirchhoff is known as the Conservation of Energy.

Kirchhoffs Voltage Law

kirchhoffs voltage law

Starting at any point in the loop continue in the same direction noting the direction of all the voltage drops, either positive or negative, and returning back to the same starting point. It is important to maintain the same direction either clockwise or anti-clockwise or the final voltage sum will not be equal to zero. We can use Kirchhoff’s voltage law when analysing series circuits.

When analysing either DC circuits or AC circuits using Kirchhoffs Circuit Laws a number of definitions and terminologies are used to describe the parts of the circuit being analysed such as: node, paths, branches, loops and meshes. These terms are used frequently in circuit analysis so it is important to understand them.

Common DC Circuit Theory Terms:

  • • Circuit – a circuit is a closed loop conducting path in which an electrical current flows.
  • • Path – a single line of connecting elements or sources.
  • • Node – a node is a junction, connection or terminal within a circuit were two or more circuit elements are connected or joined together giving a connection point between two or more branches. A node is indicated by a dot.
  • • Branch – a branch is a single or group of components such as resistors or a source which are connected between two nodes.
  • • Loop – a loop is a simple closed path in a circuit in which no circuit element or node is encountered more than once.
  • • Mesh – a mesh is a single open loop that does not have a closed path. There are no components inside a mesh.

Note that:

    Components are said to be connected together in Series if the same current value flows through all the components.

    Components are said to be connected together in Parallel if they have the same voltage applied across them.

A Typical DC Circuit

kirchhoffs circuit law

Kirchhoffs Circuit Law Example No1

Find the current flowing in the 40Ω Resistor, R3

kirchhoffs law example

The circuit has 3 branches, 2 nodes (A and B) and 2 independent loops.

Using Kirchhoffs Current LawKCL the equations are given as:

At node A :    I1 + I2 = I3

At node B :    I3 = I1 + I2

Using Kirchhoffs Voltage LawKVL the equations are given as:

Loop 1 is given as :    10 = R1 I1 + R3 I3 = 10I1 + 40I3

Loop 2 is given as :    20 = R2 I2 + R3 I3 = 20I2 + 40I3

Loop 3 is given as :    10 – 20 = 10I1 – 20I2

As I3 is the sum of I1 + I2 we can rewrite the equations as;

Eq. No 1 :    10 = 10I1 + 40(I1 + I2)  =  50I1 + 40I2

Eq. No 2 :    20 = 20I2 + 40(I1 + I2)  =  40I1 + 60I2

We now have two “Simultaneous Equations” that can be reduced to give us the values of I1 and I2 

Substitution of I1 in terms of I2 gives us the value of I1 as -0.143 Amps

Substitution of I2 in terms of I1 gives us the value of I2 as +0.429 Amps

As :    I3 = I1 + I2

The current flowing in resistor R3 is given as :    -0.143 + 0.429 = 0.286 Amps

and the voltage across the resistor R3 is given as :    0.286 x 40 = 11.44 volts

The negative sign for I1 means that the direction of current flow initially chosen was wrong, but never the less still valid. In fact, the 20v battery is charging the 10v battery.

Application of Kirchhoffs Circuit Laws

These two laws enable the Currents and Voltages in a circuit to be found, ie, the circuit is said to be “Analysed”, and the basic procedure for using Kirchhoff’s Circuit Laws is as follows:

  • 1. Assume all voltages and resistances are given. ( If not label them V1, V2,… R1, R2, etc. )
  • 2. Label each branch with a branch current. ( I1, I2, I3 etc. )
  • 3. Find Kirchhoff’s first law equations for each node.
  • 4. Find Kirchhoff’s second law equations for each of the independent loops of the circuit.
  • 5. Use Linear simultaneous equations as required to find the unknown currents.

As well as using Kirchhoffs Circuit Law to calculate the various voltages and currents circulating around a linear circuit, we can also use loop analysis to calculate the currents in each independent loop which helps to reduce the amount of mathematics required by using just Kirchhoff’s laws. In the next tutorial about DC circuits, we will look at Mesh Current Analysis to do just that.