Intro To C++ Object Model - Richard Powell - CppCon 2015
Intro To C++ Object Model - Richard Powell - CppCon 2015
$ make intro
c++ intro.cpp -o intro
$ ./intro
hello world
• make’s auto deduction rules will deduce they should use $CXX to
convert cpp files to executables.
P r oTip!
$ ./intro
hello world
• “In this way, the data structure becomes an object that includes
both data and functions.” - http://www.webopedia.com/TERM/O/
object_oriented_programming_OOP.html
C++ Object model
C++ Object model
• “An object is a region of storage.” ISO N3690: § 1.8 [intro.object]
C++ Object model
• “An object is a region of storage.” ISO N3690: § 1.8 [intro.object]
• Constraints:
C++ Object model
• “An object is a region of storage.” ISO N3690: § 1.8 [intro.object]
• Constraints:
• Constraints:
#include <stdio.h>
typedef struct
{
float real;
float imag; A sizeof(Complex): 4
} Complex;
int main()
{
printf("sizeof(float): %ld\n", sizeof(float));
printf("sizeof(Complex): %ld\n", sizeof(Complex));
B sizeof(Complex): 8
C sizeof(Complex): 16
quiz_c_size.c: $ make quiz_c_size
$ ./quiz_c_size
sizeof(float): 4
#include <stdio.h>
typedef struct
{
float real;
float imag; A sizeof(Complex): 4
} Complex;
int main()
{
printf("sizeof(float): %ld\n", sizeof(float));
printf("sizeof(Complex): %ld\n", sizeof(Complex));
B sizeof(Complex): 8
C sizeof(Complex): 16
quiz_c_offset.c: $ make quiz_c_offset
$ ./quiz_c_offset
address of c: 0x10080
#include <stdio.h>
typedef struct
{
float real; address of c.real: 0x10080
float imag;
A address of c.imag: 0x10084
} Complex;
int main()
{
Complex c; address of c.real: 0x10084
printf("address of c: %p\n", &c); address of c.imag: 0x10080
printf("address of c.real: %p\n", &c.real); B
printf("address of c.imag: %p\n", &c.imag);
}
#include <stdio.h>
typedef struct
{
float real; address of c.real: 0x10080
float imag;
A address of c.imag: 0x10084
} Complex;
int main()
{
Complex c; address of c.real: 0x10084
printf("address of c: %p\n", &c); address of c.imag: 0x10080
printf("address of c.real: %p\n", &c.real); B
printf("address of c.imag: %p\n", &c.imag);
}
#include <stdio.h>
typedef struct
{
float real;
float imag;
} Complex;
int main()
{
Complex c;
printf("address of c: %p\n", &c);
printf("address of c.real: %p\n", &c.real);
printf("address of c.imag: %p\n", &c.imag); Complex
float
} 0x10084
imag
float
real 0x10080
0x10080 c
quiz_size1.cpp: $ make quiz_size1
$ ./quiz_size1
sizeof(float): 4
#include <iostream>
struct Complex
{
float real;
float imag; A sizeof(Complex): 4
};
int main()
{
std::cout<<"sizeof(float): "<<sizeof(float)<<"\n";
std::cout<<"sizeof(Complex): "<<sizeof(Complex)<<"\n";
B sizeof(Complex): 8
C sizeof(Complex): 16
quiz_size1.cpp: $ make quiz_size1
$ ./quiz_size1
sizeof(float): 4
#include <iostream>
struct Complex
{
float real;
float imag; A sizeof(Complex): 4
};
int main()
{
std::cout<<"sizeof(float): "<<sizeof(float)<<"\n";
std::cout<<"sizeof(Complex): "<<sizeof(Complex)<<"\n";
B sizeof(Complex): 8
C sizeof(Complex): 16
quiz_offset1.cpp: $ make quiz_offset1
$ ./quiz_offset1
address of c: 0x10080
#include <iostream>
using std::cout;
struct Complex
{ address of c.real: 0x10080
float real;
float imag; A address of c.imag: 0x10084
};
int main()
{
address of c.real: 0x10084
Complex c;
cout<<"address of c: "<<&c<<"\n"; B address of c.imag: 0x10080
cout<<"address of c.real: "<<&c.real<<"\n";
cout<<"address of c.imag: "<<&c.imag<<"\n";
}
#include <iostream>
using std::cout;
#include <iostream>
using std::cout;
struct Complex
{ address of c.real: 0x10080
float real;
float imag; A address of c.imag: 0x10084
};
int main()
{
address of c.real: 0x10084
Complex c;
cout<<"address of c: "<<&c<<"\n"; B address of c.imag: 0x10080
cout<<"address of c.real: "<<&c.real<<"\n";
cout<<"address of c.imag: "<<&c.imag<<"\n";
}
#include <iostream>
using std::cout;
struct Complex
{ address of c.real: 0x10080
float real;
float imag; A address of c.imag: 0x10084
};
int main()
{
address of c.real: 0x10084
Complex c;
cout<<"address of c: "<<&c<<"\n"; B address of c.imag: 0x10080
cout<<"address of c.real: "<<&c.real<<"\n";
cout<<"address of c.imag: "<<&c.imag<<"\n";
}
is_pod
demo_is_pod.cpp:
#include <iostream>
#include <type_traits> $ make demo_is_pod
using std::cout; $ ./demo_is_pod
is Complex a POD? yes
struct Complex
{
float real;
float imag;
};
int main()
{
cout<<"is Complex a POD? "<<
(std::is_pod<Complex>() ? "yes" : "no")<<"\n";
}
quiz_size_class.cpp: $ make quiz_size_class
$ ./quiz_size_class
sizeof(float): 4
#include <iostream>
using std::cout;
class Complex
{
float real;
float imag;
A sizeof(Complex): 4
};
int main()
{
cout<<"sizeof(float): "<<sizeof(float)<<"\n"; B sizeof(Complex): 8
cout<<"sizeof(Complex): "<<sizeof(Complex)<<"\n";
}
C sizeof(Complex): 16
quiz_size_class.cpp: $ make quiz_size_class
$ ./quiz_size_class
sizeof(float): 4
#include <iostream>
using std::cout;
class Complex
{
float real;
float imag;
A sizeof(Complex): 4
};
int main()
{
cout<<"sizeof(float): "<<sizeof(float)<<"\n"; B sizeof(Complex): 8
cout<<"sizeof(Complex): "<<sizeof(Complex)<<"\n";
}
C sizeof(Complex): 16
• In C++, the only difference between a struct and a class is the
default accessor value
struct Complex
class Complex
{
{
};
float real;
float imag; == private:
float real;
float imag;
};
quiz_derived.cpp: $ make quiz_derived
$ ./quiz_derived
sizeof(float): 4
#include <iostream>
using std::cout;
struct Complex
{ sizeof(Complex): 8
float real; A sizeof(Derived): 8
float imag;
};
#include <iostream>
using std::cout;
struct Complex
{ sizeof(Complex): 8
float real; A sizeof(Derived): 8
float imag;
};
#include <iostream>
using std::cout;
address of d.real: 0x10080
struct Complex
{ address of d.imag: 0x10084
float real; A address of d.angle: 0x10088
float imag;
};
#include <iostream>
using std::cout;
address of d.real: 0x10080
struct Complex
{ address of d.imag: 0x10084
float real; A address of d.angle: 0x10088
float imag;
};
struct Complex
{ struct Derived
float real; {
float imag; struct {
};
{ float angle;
float angle; };
};
Compiler’s view of the stack
#include <iostream>
struct Complex
{
float real;
float imag;
};
int main()
{
Derived d;
Complex& c = d;
}
Compiler’s view of the stack
What d looks like:
#include <iostream>
struct Complex
{
float real;
float imag;
};
struct Complex
{
float real;
float imag;
};
#include <iostream>
#include <cmath>
using std::cout;
struct Complex
{
float Abs() const { return std::hypot(real, imag); }
float real;
A sizeof(Complex): 4
float imag;
};
int main()
{ B sizeof(Complex): 8
cout<<"sizeof(float): "<<sizeof(float)<<"\n";
cout<<"sizeof(Complex): "<<sizeof(Complex)<<"\n";
}
C sizeof(Complex): 16
quiz_mem_func.cpp: $ make quiz_mem_func
$ ./quiz_mem_func
sizeof(float): 4
#include <iostream>
#include <cmath>
using std::cout;
struct Complex
{
float Abs() const { return std::hypot(real, imag); }
float real;
A sizeof(Complex): 4
float imag;
};
int main()
{ B sizeof(Complex): 8
cout<<"sizeof(float): "<<sizeof(float)<<"\n";
cout<<"sizeof(Complex): "<<sizeof(Complex)<<"\n";
}
C sizeof(Complex): 16
Conceptually how member function are formed
struct Complex
{
float Abs() const;
float real;
float imag;
};
Complex c;
auto v = c.Abs();
float Complex::Abs() const
{
return std::hypot(real, imag);
}
Complex c;
auto v = c.Abs();
A pointer the this object is added as the first argument
Complex c;
auto v = c.Abs();
A pointer the this object is added as the first argument
Complex c;
auto v = c.Abs();
The CV-qualifiers are applied to the this object
Complex c;
auto v = c.Abs();
The CV-qualifiers are applied to the this object
Complex c;
auto v = c.Abs();
The CV-qualifiers are applied to the this object
Complex c;
auto v = c.Abs();
The CV-qualifiers are applied to the this object
Complex c;
auto v = Abs(&c);
All member variables are prefixed to use the this object
Complex c;
auto v = Abs(&c);
All member variables are prefixed to use the this object
Complex c;
auto v = Abs(&c);
The compiler translates the function to a free function with
a implementation defined “name mangled” version
Complex c;
auto v = Abs(&c);
The compiler translates the function to a free function with
a implementation defined “name mangled” version
Complex c;
auto v = Abs(&c);
The compiler translates the function to a free function with
a implementation defined “name mangled” version
Complex c;
auto v = __ZNK7Complex3AbsEv(&c);
float Complex::Abs() const
{
Before return std::hypot(real, imag);
}
c++filt to translate
$ c++filt __ZNK7Complex3AbsEv
Complex::Abs() const
struct Erdos
{
void whoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
}; I am Erdos
struct Fermat : public Erdos
A I really am Erdos
{
voidwhoAmI() { cout<<"I am Fermat\n"; }
virtual void whoAmIReally() { cout<<"I really am Fermat\n"; }
};
int main()
{ I am Erdos
Erdos e; B I really am Fermat
e.whoAmI();
e.whoAmIReally();
Fermat f;
f.whoAmI();
f.whoAmIReally(); I am Fermat
} C I really am Fermat
quiz_virtual1.cpp: $ make quiz_virtual1
$ ./quiz_virtual1
I am Erdos
I really am Erdos
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
}; I am Erdos
struct Fermat : public Erdos
A I really am Erdos
{
voidwhoAmI() { cout<<"I am Fermat\n"; }
virtual void whoAmIReally() { cout<<"I really am Fermat\n"; }
};
int main()
{ I am Erdos
Erdos e; B I really am Fermat
e.whoAmI();
e.whoAmIReally();
Fermat f;
f.whoAmI();
f.whoAmIReally(); I am Fermat
} C I really am Fermat
quiz_virtual2.cpp: $ make quiz_virtual2
$ ./quiz_virtual2
I am Fermat
I really am Fermat
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
}; I am Erdos
struct Fermat : public Erdos
A I really am Erdos
{
voidwhoAmI() { cout<<"I am Fermat\n"; }
virtual void whoAmIReally() { cout<<"I really am Fermat\n"; }
};
int main()
{ I am Erdos
Fermat f; B I really am Fermat
f.whoAmI();
f.whoAmIReally();
Erdos& e = f;
e.whoAmI();
e.whoAmIReally(); I am Fermat
} C I really am Fermat
quiz_virtual2.cpp: $ make quiz_virtual2
$ ./quiz_virtual2
I am Fermat
I really am Fermat
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
}; I am Erdos
struct Fermat : public Erdos
A I really am Erdos
{
voidwhoAmI() { cout<<"I am Fermat\n"; }
virtual void whoAmIReally() { cout<<"I really am Fermat\n"; }
};
int main()
{ I am Erdos
Fermat f; B I really am Fermat
f.whoAmI();
f.whoAmIReally();
Erdos& e = f;
e.whoAmI();
e.whoAmIReally(); I am Fermat
} C I really am Fermat
#include <iostream>
using std::cout;
struct Erdos
{
void whoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
}; I am Erdos
struct Fermat : public Erdos
A I really am Erdos
{
voidwhoAmI() { cout<<"I am Fermat\n"; }
virtual void whoAmIReally() { cout<<"I really am Fermat\n"; }
};
int main()
{ I am Erdos
Fermat f; B I really am Fermat
f.whoAmI(); non-virtual functions resolved statically
f.whoAmIReally();
Erdos& e = f;
e.whoAmI();
e.whoAmIReally(); I am Fermat
} C I really am Fermat
quiz_virtual2.cpp: $ make quiz_virtual2
$ ./quiz_virtual2
I am Fermat
I really am Fermat
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
}; I am Erdos
struct Fermat : public Erdos
A I really am Erdos
{
voidwhoAmI() { cout<<"I am Fermat\n"; }
virtual void whoAmIReally() { cout<<"I really am Fermat\n"; }
};
int main()
{ I am Erdos
Fermat f; B I really am Fermat
f.whoAmI(); Virtual calls determined by object creation.
f.whoAmIReally(); Original object created as Fermat.
Fermat function is called.
Erdos& e = f;
e.whoAmI();
e.whoAmIReally(); I am Fermat
} C I really am Fermat
quiz_virtual3.cpp: $ make quiz_virtual3
$ ./quiz_virtual3
I am Erdos
I really am Erdos
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
}; I am Erdos
struct Fermat : public Erdos A I really am Erdos
{
voidwhoAmI() { cout<<"I am Fermat\n"; }
virtual void whoAmIReally() { cout<<"I really am Fermat\n"; }
};
int main()
{ I am Erdos
Erdos * e1 = new Erdos; B I really am Fermat
e1->whoAmI();
e1->whoAmIReally();
int main()
{
Erdos* e = new Erdos;
e->whoAmI();
e->whoAmIReally();
}
int main()
{
using std::unique_ptr;
using std::make_unique;
unique_ptr<Erdos> e = make_unique<Erdos>();
e->whoAmI();
e->whoAmIReally();
}
P r oTip!
int main()
{
• unique_ptr is a C++ Smart
Erdos* e = new Erdos;
e->whoAmI(); Pointer
e->whoAmIReally();
}
• make_unique: convenience
function to make unique_ptrs
int main()
{
using std::unique_ptr; I am Erdos
using std::make_unique; B I really am Fermat
unique_ptr<Erdos> e1 = make_unique<Erdos>();
e1->whoAmI();
e1->whoAmIReally();
unique_ptr<Erdos> e2 = make_unique<Fermat>();
e2->whoAmI(); I am Fermat
e2->whoAmIReally();
C I really am Fermat
}
quiz_virtual3.cpp: $ make quiz_virtual3
$ ./quiz_virtual3
I am Erdos
I really am Erdos
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
int main()
{
using std::unique_ptr; I am Erdos
using std::make_unique; B I really am Fermat
unique_ptr<Erdos> e1 = make_unique<Erdos>();
e1->whoAmI();
e1->whoAmIReally();
unique_ptr<Erdos> e2 = make_unique<Fermat>();
e2->whoAmI(); I am Fermat
e2->whoAmIReally();
C I really am Fermat
}
quiz_virtual4.cpp: $ make quiz_virtual4
$ ./quiz_virtual4
I am Erdos
I really am Erdos
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
int main()
{
using std::unique_ptr; I am Erdos
using std::make_unique; B I really am Fermat
unique_ptr<Erdos> e = make_unique<Erdos>();
e->whoAmI();
e->whoAmIReally();
unique_ptr<Fermat> f = make_unique<Fermat>();
f->whoAmI(); I am Fermat
f->whoAmIReally();
C I really am Fermat
}
quiz_virtual4.cpp: $ make quiz_virtual4
$ ./quiz_virtual4
I am Erdos
I really am Erdos
struct Erdos
{
voidwhoAmI() { cout<<"I am Erdos\n"; }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
int main()
{
using std::unique_ptr; I am Erdos
using std::make_unique; B I really am Fermat
unique_ptr<Erdos> e = make_unique<Erdos>();
e->whoAmI();
e->whoAmIReally();
unique_ptr<Fermat> f = make_unique<Fermat>();
f->whoAmI(); I am Fermat
f->whoAmIReally();
C I really am Fermat
}
$ make quiz_size3
quiz_size3.cpp: $ ./quiz_size3
sizeof(float): 4
sizeof(void*): 8
struct Complex
{
virtual ~Complex() = default;
virtual float Abs() { return std::hypot(real, imag); }
float real;
float imag; A sizeof(Complex): 8
};
sizeof(Derived): 12
int main()
{
cout<<"sizeof(float): "<<sizeof(float)<<"\n";
cout<<"sizeof(void*): "<<sizeof(void*)<<"\n";
cout<<"sizeof(Complex): "<<sizeof(Complex)<<"\n"; C sizeof(Complex): 16
cout<<"sizeof(Derived): "<<sizeof(Derived)<<"\n"; sizeof(Derived): 32
}
$ make quiz_size3
quiz_size3.cpp: $ ./quiz_size3
sizeof(float): 4
sizeof(void*): 8
struct Complex
{
virtual ~Complex() = default;
virtual float Abs() { return std::hypot(real, imag); }
float real;
float imag; A sizeof(Complex): 8
};
sizeof(Derived): 12
int main()
{
cout<<"sizeof(float): "<<sizeof(float)<<"\n";
cout<<"sizeof(void*): "<<sizeof(void*)<<"\n";
cout<<"sizeof(Complex): "<<sizeof(Complex)<<"\n"; C sizeof(Complex): 16
cout<<"sizeof(Derived): "<<sizeof(Derived)<<"\n"; sizeof(Derived): 32
}
quiz_offset3.cpp: $ make quiz_offset3
$ ./quiz_offset3
address of d: 0x10080
struct Complex
{
virtual ~Complex() = default;
virtual float Abs() { return std::hypot(real, imag); } address of d.real: 0x10080
float real; address of d.imag: 0x10084
float imag; A address of d.angle: 0x10088
};
int main()
{
Derived d;
cout<<"address of d: "<<(&d)<<"\n"; address of d.real: 0x10088
cout<<"address of d.real: "<<(&d.real)<<"\n";
cout<<"address of d.imag: "<<(&d.imag)<<"\n"; C address of d.imag: 0x1008c
cout<<"address of d.angle: "<<(&d.angle)<<"\n"; address of d.angle: 0x10090
}
quiz_offset3.cpp: $ make quiz_offset3
$ ./quiz_offset3
address of d: 0x10080
struct Complex
{
virtual ~Complex() = default;
virtual float Abs() { return std::hypot(real, imag); } address of d.real: 0x10080
float real; address of d.imag: 0x10084
float imag; A address of d.angle: 0x10088
};
int main()
{
Derived d;
cout<<"address of d: "<<(&d)<<"\n"; address of d.real: 0x10088
cout<<"address of d.real: "<<(&d.real)<<"\n";
cout<<"address of d.imag: "<<(&d.imag)<<"\n"; C address of d.imag: 0x1008c
cout<<"address of d.angle: "<<(&d.angle)<<"\n"; address of d.angle: 0x10090
}
Complex float
How member function work with virtual
imag
float
struct Complex {
virtual ~Complex() = default;
real
virtual float Abs();
float real;
float imag;
};
float Complex::Abs()
{
return std::hypot(real, imag);
}
Complex original_c;
Complex& c = original_c;
float ans = c.Abs();
Complex float
Member functions are generated as normal
imag
imag
float
struct Complex {
virtual ~Complex() = default;
real
real
virtual float Abs();
float real;
float imag;
};
Complex original_c;
Complex& c = original_c;
float ans = c.Abs();
Complex float
A table of all virtual functions is generated (the vtable)
imag
float
struct Complex {
virtual ~Complex() = default;
real
virtual float Abs();
float real;
float imag;
};
ComplexTbl
dtor*
float __ZNK7Complex3AbsEv(Complex const * this)
{
return std::hypot(this->real, this->imag);
}
float(*)
Complex original_c;
Complex& c = original_c;
float ans = c.Abs();
Complex float
The compiler silently inserts a point to the table
imag
float
struct Complex {
$$tbl$$ * vtable;
real
virtual ~Complex() = default; $$tbl$$*
virtual float Abs();
float real; vtable
float imag;
};
ComplexTbl
dtor*
float __ZNK7Complex3AbsEv(Complex const * this)
{
return std::hypot(this->real, this->imag);
}
float(*)
Complex original_c;
Complex& c = original_c;
float ans = c.Abs();
Complex float
imag
float
struct Complex {
$$tbl$$ * vtable;
real
virtual ~Complex() = default; $$tbl$$*
virtual float Abs();
float real; vtable
float imag;
};
ComplexTbl
dtor*
float __ZNK7Complex3AbsEv(Complex const * this)
{
return std::hypot(this->real, this->imag);
}
float(*)
imag
float
struct Complex {
$$tbl$$ * vtable;
real
virtual ~Complex() = default; $$tbl$$*
virtual float Abs();
float real; vtable
float imag;
};
ComplexTbl
dtor*
float __ZNK7Complex3AbsEv(Complex const * this)
{
return std::hypot(this->real, this->imag);
}
float(*)
imag
imag
float
struct Complex {
$$tbl$$ * vtable;
real
real
virtual ~Complex() = default; $$tbl$$*
virtual float Abs();
float real;
vtable
float imag;
};
ComplexTbl
dtor*
float __ZNK7Complex3AbsEv(Complex const * this)
{
return std::hypot(this->real, this->imag);
}
float(*)
Complex original_c;
Complex& c = original_c;
float ans = c.vtable[???]();
Complex float
imag
imag
float
struct Complex {
$$tbl$$ * vtable;
real
real
virtual ~Complex() = default; $$tbl$$*
virtual float Abs();
float real;
vtable
float imag;
};
ComplexTbl
dtor*
float __ZNK7Complex3AbsEv(Complex const * this)
{
return std::hypot(this->real, this->imag);
}
float(*)
Complex original_c;
Complex& c = original_c;
float ans = c.vtable[1/*OffsetOf_Abs*/]();
Complex float
imag
float
struct Complex {
$$tbl$$ * vtable;
real
virtual ~Complex() = default; $$tbl$$*
virtual float Abs();
float real;
vtable
float imag;
};
ComplexTbl
dtor*
float __ZNK7Complex3AbsEv(Complex const * this)
{
return std::hypot(this->real, this->imag);
}
float(*)
Complex original_c;
Complex& c = original_c;
float ans = c.vtable[1/*OffsetOf_Abs*/]();
Complex float
imag
float
struct Complex {
$$tbl$$ * vtable;
real
virtual ~Complex() = default; $$tbl$$*
virtual float Abs();
float real;
vtable
float imag;
};
ComplexTbl
dtor*
float __ZNK7Complex3AbsEv(Complex const * this)
{
return std::hypot(this->real, this->imag);
}
float(*)
Complex original_c;
Complex& c = original_c;
float ans = c.vtable[1/*OffsetOf_Abs*/](&c);
_const _text
struct Complex
{
virtual ~Complex() {}
virtual float Abs() { ;;; }
float real;
float imag;
};
int main()
{
Complex d;
}
_const _text
struct Complex
{
virtual ~Complex() {}
virtual float Abs() { ;;; }
float real; Complex::~Complex() {}
float imag;
};
float Complex::Abs() { ;;
int main()
{
Complex d;
}
_const _text
struct Complex
{
virtual ~Complex() {} ComplexTbl
virtual float Abs() { ;;; } dtor*
float real; Complex::~Complex() {}
float imag;
};
float(*)
float Complex::Abs() { ;;
int main()
{
Complex d;
}
_const _text
struct Complex
{
virtual ~Complex() {} ComplexTbl
virtual float Abs() { ;;; } dtor*
float real; Complex::~Complex() {}
float imag;
};
float(*)
float Complex::Abs() { ;;
Complex float
imag
float
real
int main() $$tbl$$*
{
Complex d;
} vtable
YMMV
• From Working Draft N4431, Clause 9.2, Note 13:
When in doubt…
• Read the standard:
• http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4431.pdf
_const _text
struct Complex
{
virtual ~Complex() {}
virtual float Abs() { ;;; }
float real;
float imag;
};
int main()
{
Complex c;
}
_const _text
struct Complex
{
virtual ~Complex() {}
virtual float Abs() { ;;; }
float real; Complex::~Complex() {}
float imag;
};
float Complex::Abs() { ;;
struct Derived : public Complex
{
virtual ~Derived() {}
virtual float Abs() { ;;; }
float angle;
};
int main()
{
Complex c; Derived::~Derived() {}
}
float Derived::Abs() { ;;
_const _text
struct Complex
{
virtual ~Complex() {} ComplexTbl
virtual float Abs() { ;;; } dtor*
float real; Complex::~Complex() {}
float imag;
};
float(*)
float Complex::Abs() { ;;
struct Derived : public Complex
{
virtual ~Derived() {}
virtual float Abs() { ;;; }
float angle;
};
float Derived::Abs() { ;;
float(*)
_const _text
struct Complex
{
virtual ~Complex() {} ComplexTbl
virtual float Abs() { ;;; } dtor*
float real; Complex::~Complex() {}
float imag;
};
float(*)
float Complex::Abs() { ;;
struct Derived : public Complex
{ Complex float
virtual ~Derived() {}
virtual float Abs() { ;;; } imag
float angle;
float
};
real
int main() $$tbl$$* DerivedTbl
{ dtor*
Complex c; Derived::~Derived() {}
} vtable
float Derived::Abs() { ;;
float(*)
_const _text
struct Complex
{
virtual ~Complex() {} ComplexTbl
virtual float Abs() { ;;; } dtor*
float real; Derived
Complex::~Complex() {}
float imag;
};
float
angle float(*)
float Complex::Abs() { ;;
struct Derived : public Complex
{ Complex float
virtual ~Derived() {}
virtual float Abs() { ;;; } imag
float angle;
float
};
real
int main() $$tbl$$* DerivedTbl
{ dtor*
Derived c; Derived::~Derived() {}
} vtable
float Derived::Abs() { ;;
float(*)
_const _text
struct Complex
{
virtual ~Complex() {} ComplexTbl
virtual float Abs() { ;;; } dtor*
float real; Derived
Complex::~Complex() {}
float imag;
};
float
angle float(*)
float Complex::Abs() { ;;
struct Derived : public Complex
{ Complex float
virtual ~Derived() {}
virtual float Abs() { ;;; } imag
float angle;
float
};
real
int main() $$tbl$$* DerivedTbl
{ dtor*
Derived c; Derived::~Derived() {}
} vtable
float Derived::Abs() { ;;
float(*)
Complex::Complex()
{
}
struct Complex {
$$tbl$$ * vtable;
Complex();
virtual ~Complex() = default;
virtual float Abs();
float real;
float imag;
};
Complex::Complex()
{
}
struct Complex {
$$tbl$$ * vtable;
Complex();
virtual ~Complex() = default;
virtual float Abs();
float real;
float imag;
};
Complex::Complex()
{
vtable = ComplexTbl;
}
struct Derived : public Complex {
Derived();
virtual ~Derived() = default;
virtual float Abs();
float angle;
};
Derived::Derived()
{
}
struct Derived : public Complex {
Derived();
virtual ~Derived() = default;
virtual float Abs();
float angle;
};
Derived::Derived()
{
}
struct Derived : public Complex {
Derived();
virtual ~Derived() = default;
virtual float Abs();
float angle;
};
Derived::Derived()
{
this->Complex::Complex();
vtable = DerivedTbl;
}
struct Derived : public Complex {
Derived();
virtual ~Derived() = default;
virtual float Abs();
float angle;
};
Derived::Derived()
{
this->Complex::Complex();
Complex::Complex()
vtable = DerivedTbl;
} {
vtable = ComplexTbl;
}
quiz_ctor.cpp: $ make quiz_ctor
$ ./quiz_ctor
I really am Erdos
#include <iostream>
using std::cout;
I really am Erdos
struct Erdos A
{
Erdos() { whoAmIReally(); }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
int main()
{
Erdos e;
Fermat f;
}
quiz_ctor.cpp: $ make quiz_ctor
$ ./quiz_ctor
I really am Erdos
#include <iostream>
using std::cout;
I really am Erdos
struct Erdos A
{
Erdos() { whoAmIReally(); }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
int main()
{
Erdos e;
Fermat f;
}
quiz_ctor.cpp: $ make quiz_ctor
$ ./quiz_ctor
I really am Erdos
#include <iostream>
using std::cout;
I really am Erdos
struct Erdos A
{
Erdos() { whoAmIReally(); }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
int main()
{
Erdos e; Fermat::Fermat()
Fermat f;{
this->Erdos::Erdos();
} vtable = FermatTbl;
}
quiz_ctor.cpp: $ make quiz_ctor
$ ./quiz_ctor
I really am Erdos
#include <iostream>
using std::cout;
I really am Erdos
struct Erdos A
{
Erdos() { whoAmIReally(); }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
int main()
{
Erdos e; Fermat::Fermat()
Fermat f;{ Erdos::Erdos()
this->Erdos::Erdos();
{
} vtable = FermatTbl;
vtable = ErdosTbl;
} whoAmIReally();
}
quiz_ctor.cpp: $ make quiz_ctor
$ ./quiz_ctor
I really am Erdos
#include <iostream>
using std::cout;
I really am Erdos
struct Erdos A
{
Erdos() { whoAmIReally(); }
virtual void whoAmIReally() { cout<<"I really am Erdos\n"; }
};
int main()
{
Erdos e; Fermat::Fermat()
Fermat f;{ Erdos::Erdos()
this->Erdos::Erdos();
NEVER call virtual functions
} {
}
vtable = FermatTbl;
vtable = ErdosTbl;
whoAmIReally();
in a constructor!!!
}
C++ Object model
• C++ object model is the way objects exist in memory
• http://www.webopedia.com/TERM/O/
object_oriented_programming_OOP.html
• http://cppreference.com
Questions?