OOp in C++

Part III

Member pointers

class ClassName {
    int i1, i2, i3;
    double d1, d2;
    void f1() {}
    void f2() {}
    void g1(int, char) {}
    void g2(int, char) {}
};
void printIntMember(const ClassName& c, int memberIdx) {
    switch(memberIdx) {
        case 1:
            std::cout << c.i1; break;
        case 2:
            std::cout << c.i2; break;
        case 3:
            std::cout << c.i3; break;
        default: assert(false);
    }
}

Member pointers

class ClassName {
    int i1, i2, i3;
    double d1, d2;
    void f1() {}
    void f2() {}
    void g1(int, char) {}
    void g2(int, char) {}
};
void printIntMember(const ClassName& c, int C::* member){
    std::cout << c.*member;
}

Member pointers

class ClassName {
    int i1, i2, i3;
    double d1, d2;
    void f1() {}
    void f2() {}
    void g1(int, char) {}
    void g2(int, char) {}
};
void printIntMember(const ClassName& c, int C::* member){
    std::cout << c.*member;
}

void printIntMember(const ClassName* c, int C::* member){
    std::cout << c->*member;
}

Member pointers

class ClassName {
    int i1, i2, i3;
    double d1, d2;
    void f1() {}
    void f2() {}
    void g1(int, char) {}
    void g2(int, char) {}
};
void printIntMember(const ClassName& c, int C::* member){
    std::cout << c.*member;
}

void printIntMember(const ClassName* c, int C::* member){
    std::cout << c->*member;
}

void callMember(ClassName& c, void(ClassName::*member)()){
    c.*member();
}

void callMember(ClassName* c, void(ClassName::*member)(int, char)){
    c.*member(2, 'c');
}

Member pointers

class ClassName {
    int i1, i2, i3;
    double d1, d2;
    void f1() {}
    void f2() {}
    void g1(int, char) {}
    void g2(int, char) {}
};
void printIntMember(const ClassName& c, int C::* member){
    std::cout << c.*member;
}
void printIntMember(const ClassName* c, int C::* member){
    std::cout << c->*member;
}
void callMember(ClassName& c, void(ClassName::*member)()){
    c.*member();
}
void callMember(ClassName* c, void(ClassName::*member)(int, char)){
    c.*member(2, 'c');
}
ClassName c1{};
printIntMember(c1, &ClassName::i2);
printIntMember(&c1, &ClassName::i1);
callMember(c1, &ClassName::f2);
callMember(&c1, &ClassName::g1);

User defined CONVERSIONS

conversions

class String {
    size_t size;
    char* data;
public:
    // Make string from char ptr
    String(const char* data_) :
        size{std::strlen(data_)},
        data{new char[size]}
    {
        std::strncpy(data, data_, size);
    }
    ~String()
    {
        delete[] data;
    }
    
    // Make char ptr from string?
};

User defined CONVERSIONS

conversions

class String {
    size_t size;
    char* data;
public:
    // Make String from char ptr
    String(const char* data_) :
        size{std::strlen(data_)},
        data{new char[size]}
    {
        std::strncpy(data, data_, size);
    }
    ~String()
    {
        delete[] data;
    }

    // Make char ptr from String?
    const char* c_str() const {
        return data;
    }
};

User defined CONVERSIONS

conversions

class String {
    size_t size;
    char* data;
public:
    String(const char* data_) :
        size{std::strlen(data_)},
        data{new char[size]}
    {
        std::strncpy(data, data_, size);
    }
    ~String()
    {
        delete[] data;
    }

    const char* c_str() const {
        return data;
    }
    
    operator const char*() const {
    	return data;
    }
};

User defined CONVERSIONS

conversions

class String {
    size_t size;
    char* data;
public:
    explicit String(const char* data_) :
        size{std::strlen(data_)},
        data{new char[size]}
    {
        std::strncpy(data, data_, size);
    }
    ~String()
    {
        delete[] data;
    }

    const char* c_str() const {
        return data;
    }
    
    explicit operator const char*() const {
    	return data;
    }
};

friends

class A {
private:
    int secret;
};
void printA(const A& a) {
    std::cout << "secret: " << a.secret;
}

class SecretWriter {
    int toWrite;

    void write(A& a) {
        a.secret = toWrite;
    }
};

friends

class A {
private:
    int secret;
    
    friend void printA(const A& a);
    friend class SecretWriter;
};
void printA(const A& a) {
    std::cout << "secret: " << a.secret;
}

class SecretWriter {
    int toWrite;

    void write(A& a) {
        a.secret = toWrite;
    }
};

friends

class DeclaredType;

class ClassName {
private:
    ...
    
    friend return_t func1(arg1_t, arg2_t /*...*/);
    
    friend return_t func2(arg1_t arg1, arg2_t arg2 /*...*/) {
      /* definition... */
    }
    
    friend class UndeclaredClass;
    
    friend DeclaredType;
};

friend return_t func1(arg1_t arg1, arg2_t arg2 /*...*/) {
    /* definition... */
}

friends

class A {
    friend class B;
}

class B {
    friend class C;
}

class C {
    
}

A

B

C

operator overloading

overloading

struct Vec {
    double x, y, z;
    
    static Vec sum(const Vec& v1, const Vec& v2) {
        return { v1.x + v2.x, 
                 v1.y + v2.y, 
                 v3.z + v3.z };
    }
    static Vec diff(const Vec& v1, const Vec& v2) {
        return { v1.x - v2.x,
                 v1.y - v2.y,
                 v3.z - v3.z };
    }
    static Vec mult(const Vec& v, float s) {
        return { v.x * s,
                 v.y * s,
                 v.z * s };
    }
    static Vec mult(float s, const Vec& v) {
        return mult(v, s);
    }
};
Vec v1 = { 1.5, 2.5, 3.5 };
Vec v2 = { 2.5, 3.5, 4.5 };

Vec u1 = Vec::sum(v1, v2);
// { 4.0, 6.0, 8.0 }
Vec u2 = Vec::diff(v2, v1);
// { 1.0, 1.0, 1.0 }
Vec u3 = Vec::mult(v1, 2.0);
// { 3.0, 5.0, 7.0 }

operator overloading

overloading

struct Vec {
    double x, y, z;
};

Vec sum(const Vec& v1, const Vec& v2) {
    return { v1.x + v2.x, 
             v1.y + v2.y, 
             v3.z + v3.z };
}
Vec diff(const Vec& v1, const Vec& v2) {
    return { v1.x - v2.x,
             v1.y - v2.y,
             v3.z - v3.z };
}
Vec mult(const Vec& v, float s) {
    return { v.x * s,
             v.y * s,
             v.z * s };
}
Vec mult(float s, const Vec& v) {
    return mult(v, s);
}
Vec v1 = { 1.5, 2.5, 3.5 };
Vec v2 = { 2.5, 3.5, 4.5 };

Vec u1 = sum(v1, v2);
// { 4.0, 6.0, 8.0 }
Vec u2 = diff(v2, v1);
// { 1.0, 1.0, 1.0 }
Vec u3 = mult(v1, 2.0);
// { 3.0, 5.0, 7.0 }

operator overloading

overloading

Vec v1 = { 1.5, 2.5, 3.5 };
Vec v2 = { 2.5, 3.5, 4.5 };

Vec u1 = sum(v1, v2);
// { 4.0, 6.0, 8.0 }
Vec u2 = diff(v2, v1);
// { 1.0, 1.0, 1.0 }
Vec u3 = mult(v1, 2.0);
// { 3.0, 5.0, 7.0 }
struct Vec {
    double x, y, z;
    
    friend Vec sum(const Vec& v1, const Vec& v2) {
        return { v1.x + v2.x, 
                 v1.y + v2.y, 
                 v3.z + v3.z };
    }
    friend Vec diff(const Vec& v1, const Vec& v2) {
        return { v1.x - v2.x,
                 v1.y - v2.y,
                 v3.z - v3.z };
    }
    friend Vec mult(const Vec& v, float s) {
        return { v.x * s,
                 v.y * s,
                 v.z * s };
    }
    friend Vec mult(float s, const Vec& v) {
        return mult(v, s);
    }
};

operator overloading

overloading

Vec v1 = { 1.5, 2.5, 3.5 };
Vec v2 = { 2.5, 3.5, 4.5 };

Vec u1 = v1 + v2;
// Vec u1 = v1 + v2;
Vec u2 = v2 - v1;
// { 1.0, 1.0, 1.0 }
Vec u3 = v1 * 2.0;
// { 3.0, 5.0, 7.0 }
struct Vec {
    double x, y, z;
    
    friend Vec operator+(const Vec& v1, const Vec& v2) {
        return { v1.x + v2.x, 
                 v1.y + v2.y, 
                 v3.z + v3.z };
    }
    friend Vec operator-(const Vec& v1, const Vec& v2) {
        return { v1.x - v2.x,
                 v1.y - v2.y,
                 v3.z - v3.z };
    }
    friend Vec operator*(const Vec& v, float s) {
        return { v.x * s,
                 v.y * s,
                 v.z * s };
    }
    friend Vec operator*(float s, const Vec& v) {
        return v * s;
    }
};
Vec v1 = { 1.5, 2.5, 3.5 };
Vec v2 = { 2.5, 3.5, 4.5 };

Vec u1 = operator+(v1, v2);
// { 4.0, 6.0, 8.0 }
Vec u2 = operator-(v2, v1);
// { 1.0, 1.0, 1.0 }
Vec u3 = operator*(v1, 2.0);
// { 3.0, 5.0, 7.0 }

operator overloading

overloading

Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)

operator overloading

overloading

class C {
    ret_t operator@() { ... }
};
struct Vec {
    float x, y, z;
    Vec operator-() const { 
        return {-x, -y, -z};
    }
};
class C {};
ret_t operator@(C c) { ... }
struct Vec {
    float x, y, z;
};
Vec& operator--(Vec& v) { 
    --v.x; --v.y; --v.z;
    return v;
}
+

-

*

&

~

!

++

--
Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)

operator overloading

overloading

class C {
    ret_t operator@(int) {...}
};
struct Fr {
  int num, denom;
  Fr operator++(int) { 
    Fr orig{f.num, f.denom};
    f.num += f.denom;
    return cpy;
  }
};
class C {};

ret_t operator@(C, int) {...}
struct Fr {
    int num, denom;
};
Fr operator++(Fr& f, int) { 
    Fr orig{f.num, f.denom};
    f.num += f.denom;
    return cpy;
}
++

--
Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)

operator overloading

overloading

class C {
    ret_t operator@(T t) {...}
};
struct Fr {
    int num, denom;
    Fr& operator+=(int n) { 
        num += denom * n;
        return *this;
    }
};
class C {};

ret_t operator@(C, T) {...}
struct Fr {
    int num, denom;
};
std::ostream& operator<<(
  std::ostream& os, const Fr& f){
    os << f.num << f.denom;
    return os;
}
+

-

*

/

%
==

!=

>

<

>=

<=

<=>
&&

||

&

|


^

<<

>>
+=

-=

*=

/=

%=

&=

|=


^=

<<=

>>=
->*

,
Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)

operator overloading

overloading

struct Fr {
    int num, denom;
    Fr operator+(int n) const { 
        Fr cpy{*this};
        cpy.num += denom * n;
        return cpy;
    }
};
struct Fr {
    int num, denom;
};
bool operator<(Fr lhs, Fr rhs){
    return lhs.num * rhs.denom
         < lhs.denom * rhs.num;
}
+

-

*

/

%
==

!=

>

<

>=

<=

<=>
&&

||

&

|


^

<<

>>
+=

-=

*=

/=

%=

&=

|=


^=

<<=

>>=
->*

,
Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)

operator overloading

overloading

struct Point {
  int x, y;
  auto operator<=>(const Point&) const = default;
  bool operator==(const Point&) const = default;
};
+

-

*

/

%
==

!=

>

<

>=

<=

<=>
&&

||

&

|


^

<<

>>
+=

-=

*=

/=

%=

&=

|=


^=

<<=

>>=
->*

,
Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)

operator overloading

overloading

class C {
    ret_t operator()(args) {...}
};
struct adder {
    int delta;
    int operator()(int n) {
        return n + delta;
    }
};

adder f{3};
// f(2) == 5
// f(6) == 9
f.delta = 4;
// f(6) == 10
Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)
struct functor {
     bool operator()(int a, int b) {
         return (a % 3) < (b % 3);
     }
};

vector<int> v{3, 4, 8, 2, 1, 8};
std::sort(v.begin(), v.end(), functor{});
// {3, 1, 4, 2, 8, 8}

operator overloading

overloading

class C {
    ret_t operator[](T idx) {...}
};
Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)
class ar {
     int* data;
public:
     ...
     int& operator[](size_t i) {
         return data[i]; 
     }
     const int& operator[](size_t i) const {
         return data[i]; 
     }
};

operator overloading

overloading

class C {
    ret_t operator->() {...}
};
Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)
class string_ptr {
    std::string data;
public:
    std::string* operator->() {
        return &data;
    }
};
struct a {
    void f();
};
struct b {
    a* operator->();
};
struct c {
    b operator->();
};
struct d {
    c operator->();
};
d obj;
obj->f();
// (obj.operator->().operator->().operator->())->f();

operator overloading

overloading

Operator name Syntax Member function Non member function
Unary prefix operator @a a.operator@() operator@(a)
Unary postfix operator a@ a.operator@(0) operator@(a, 0)
Binary infix operator a@b a.operator(b) operator@(a, b)
Call operator a(args) a.operator()(args)
Subscript operator a[idx] a.operator[](idx)
Arrow operator a-> a.operator->()
Assignment operator a=b a.operator=(b)

To be continued...

OOp in C++

Part III

RAII

inheritance

virtual

  • constructor
  • member initializer list
  • destructor
  • default constructor
  • std::initializer_list
  • in-class initializer
  • copy ctor
  • cpy assign op
  • move ctor
  • mv assign op
  • default members
  • deleted members
  • rule of 0
  • rule of 3/5
  • smart-ptrs
  • converting constructor
  • explicit specifier
  • is-a relation
  • has-a relation
  • public inheritance
  • final specifier
  • using declaration
  • empty base optimization
  • protected members
  • private & protected inheritance
  • multiple inheritance
  • diamond problem
  • base method hiding problem
  • virtual methods
  • override specifier
  • dynamic type
    • RTTI
    • dynamic_cast
    • typeid
    • vtables
  • by value passing problem
  • pure virtual function
  • abstract class

misc

  • friends
  • nested members
  • conversion operators
  • operator overloading
  • member pointers
  • unions
    • std optional
    • std variant
    • std any
  • member pointers
  • conversion operators
  • friends
  • operator overloading
  • smart-ptrs
  • ownership
  • copy ctor
  • cpy assign op
  • move ctor
  • mv assign op
  • rule of 0
  • rule of 3/5