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
Object Oriented Programming Part 3
By Jan Bielak
Object Oriented Programming Part 3
A presentation about member pointers, user defined conversions, friends and operator overloading in C++. It is presented here: https://www.youtube.com/watch?v=C1javGeyR_w .
- 632