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*
 
}