#include <iostream>
int main()
{
std::cout << "Hi, I'm Borislav!\n";
std::cout << "These slides are here: https://is.gd/oopcpp\n";
return 0;
}
#include <iostream>
int main()
{
std::cout << "Hi, I'm Borislav!\n";
std::cout << "These slides are here: https://is.gd/oopcpp\n";
return 0;
}
A part of a program which deals with the real world rules that determine how data is obtained, stored and processed.
The part which deals with the software's purpose
int a;
int b;
cin >> a >> b;
cout << a + b << '\n';
Business logic: adding two integers
The part which deals with the software's purpose
int a;
int b;
cin >> a >> b;
cout << a + b << '\n';
Business logic: adding two integers
The part which deals with the software's purpose
FirstInteger a;
SecondInteger b;
input.obtainValues(a, b);
gui.display(a + b);
Business logic: adding two integers
The part which deals with the software's purpose
FirstInteger a;
SecondInteger b;
input.obtainValues(a, b);
gui.display(a + b);
Business logic: adding two integers
Presentation, i/o...
FirstInteger a;
SecondInteger b;
input.obtainValues(a, b);
gui.display(a + b);
Non-business logic
Complex software doesn't mean complex business logic.
_
Simple. Right?
People don't seem to want to write business logic in C++
Note that there still is a lot of underlying C++ in such projects
Well... is there a problem with that?
Why don't people use C++?
... with dynamic polymorphism
People forget that C++ is an OOP language
But most importantly...
Software is written by human beings
Human beings think in terms of objects
Which languages thrive in fields with heavy business logic?
Almost all are object-oriented ones.
function f(shape) {
// Everything that has a draw method works
shape.draw();
}
Square = function () {
this.draw = function() {
console.log("Square");
}
};
Circle = function () {
this.draw = function() {
console.log("Circle");
}
};
f(new Square);
f(new Circle);
struct Shape {
virtual void draw(ostream& out) const = 0;
}
void f(const Shape& s) {
s.draw(cout);
}
struct Square : public Shape {
virtual void draw(ostream& out) const override { out << "Square\n"; }
};
struct Circle : public Shape {
virtual void draw(ostream& out) const override { out << "Circle\n"; }
};
int main() {
f(Square{});
f(Circle{});
}
However modern C++ is a pretty powerful language.
Boost.TypeErasure, Dyno, Folly.Poly, [Boost].TE
using Shape = Library_Magic(void, draw, (ostream&));
void f(const Shape& s) {
s.draw(cout);
}
struct Square {
void draw(ostream& out) const { out << "Square\n"; }
};
struct Circle {
void draw(ostream& out) const { out << "Circle\n"; }
};
int main() {
f(Square{});
f(Circle{});
}
Boost.TypeErasure, Dyno, Folly.Poly, [Boost].TE
using Shape = Library_Magic(void, draw, (ostream&));
void f(const Shape& s) {
s.draw(cout);
}
struct Square {
void draw(ostream& out) const { out << "Square\n"; }
};
struct Circle {
void draw(ostream& out) const { out << "Circle\n"; }
};
int main() {
f(Square{});
f(Circle{});
}
struct Shape {
// virtual table
std::function<void(ostream&)> draw;
std::function<int()> area;
// fill the virtual table when constructing
template <typename T>
Shape(const T& t) {
draw = std::bind(&T::draw, &t);
area = std::bind(&T::area, &t);
}
};
struct Shape {
// virtual table
std::function<void(ostream&)> draw;
std::function<int()> area;
// fill the virtual table when constructing
template <typename T>
Shape(const T& t) {
draw = std::bind(&T::draw, &t);
area = std::bind(&T::area, &t);
}
};
struct Shape {
// virtual table
std::function<void(ostream&)> draw;
std::function<int()> area;
// fill the virtual table when constructing
template <typename T>
Shape(const T& t) {
draw = std::bind(&T::draw, &t);
area = std::bind(&T::area, &t);
}
};
This, of course, is a simple and naive implementation. There's lots of room for optimization
struct Shape {
// virtual table
const void* m_obj;
void (*m_draw)(const void*, ostream&);
void draw() const {
return m_draw(m_obj);
}
template <typename T>
Shape(const T& t) {
m_obj = &t;
m_draw = [](const void* obj, ostream& out) {
auto t = reinterpret_cast<const T*>(obj);
t->draw(out);
};
}
};
struct Shape {
// virtual table
const void* m_obj;
void (*m_draw)(const void*, ostream&);
void draw() const {
return m_draw(m_obj);
}
template <typename T>
Shape(const T& t) {
m_obj = &t;
m_draw = [](const void* obj, ostream& out) {
auto t = reinterpret_cast<const T*>(obj);
t->draw(out);
};
}
};
struct Shape {
// virtual table
const void* m_obj;
void (*m_draw)(const void*, ostream&);
void draw() const {
return m_draw(m_obj);
}
template <typename T>
Shape(const T& t) {
m_obj = &t;
m_draw = [](const void* obj, ostream& out) {
auto t = reinterpret_cast<const T*>(obj);
t->draw(out);
};
}
};
Square.prototype.area = function() {
return this.side * this.side;
}
Circle.prototype.area = function() {
return this.radius * this.radius * Math.PI;
}
s = new Square;
s.side = 5;
console.log(s.area()); // 25
struct Shape {
virtual void draw(ostream& out) const = 0;
}
struct Square : public Shape {
virtual void draw(ostream& out) const override { out << "Square\n"; }
int side;
};
int main()
{
shared_ptr<Shape> ptr = make_shared<Square>();
cout << ptr->area() << '\n'; // ??
}
struct Shape {
virtual void draw(ostream& out) const = 0;
virtual double area() const = 0;
}
struct Square : public Shape {
virtual void draw(ostream& out) const override { out << "Square\n"; }
virtual double area() const override { return side * side; }
double side;
};
int main()
{
shared_ptr<Shape> ptr = make_shared<Square>();
cout << ptr->area() << '\n';
}
And what if we can't just edit the classes?
Not to be confused with extension methods or UCS
declare_method(double, area, (virtual_<const Shape&> s);
define_method(double, area, (const Square& s)
{
return s.area * s.area;
}
int main() {
shared_ptr<Shape> ptr = make_shared<Square>();
cout << area(ptr) << '\n';
}
Not to be confused with extension methods or UCS
declare_method(double, area, (virtual_<const Shape&> s);
define_method(double, area, (const Square& s)
{
return s.area * s.area;
}
int main() {
shared_ptr<Shape> ptr = make_shared<Square>();
cout << area(ptr) << '\n';
}
// declare method
using area_func = double (*)(const Shape*);
using area_func_getter = area_func (*)(const Shape*);
std::vector<area_func_getter> area_getters;
double area(Shape* s) {
for(auto g : area_getters) {
auto func = g();
if(func) return func(s);
}
throw error("Object doesn't implement area");
}
// define method
double area_for_square(const Square&);
double area_for_square_call(const Shape* s) {
auto square = static_cast<const Square*>(s);
return area_for_square(*square);
}
area_func area_for_square_getter(const Shape* s) {
return dynamic_cast<const Square*>(s) ? area_for_square_call : nullptr;
}
auto register_area_for_square = []() {
area_getters.push_back(area_for_square_getter);
return area_getters.size();
}();
double area_for_square(const Square&) // user defines after this
// declare method
using area_func = double (*)(const Shape*);
using area_func_getter = area_func (*)(const Shape*);
std::vector<area_func_getter> area_getters;
double area(Shape* s) {
for(auto g : area_getters) {
auto func = g();
if(func) return func(s);
}
throw error("Object doesn't implement area");
}
// define method
double area_for_square(const Square&);
double area_for_square_call(const Shape* s) {
auto square = static_cast<const Square*>(s);
return area_for_square(*square);
}
area_func area_for_square_getter(const Shape* s) {
return dynamic_cast<const Square*>(s) ? area_for_square_call : nullptr;
}
auto register_area_for_square = []() {
area_getters.push_back(area_for_square_getter);
return area_getters.size();
}();
double area_for_square(const Square&) // user defines after this
// declare method
using area_func = double (*)(const Shape*);
using area_func_getter = area_func (*)(const Shape*);
std::vector<area_func_getter> area_getters;
double area(Shape* s) {
for(auto g : area_getters) {
auto func = g();
if(func) return func(s);
}
throw error("Object doesn't implement area");
}
// define method
double area_for_square(const Square&);
double area_for_square_call(const Shape* s) {
auto square = static_cast<const Square*>(s);
return area_for_square(*square);
}
area_func area_for_square_getter(const Shape* s) {
return dynamic_cast<const Square*>(s) ? area_for_square_call : nullptr;
}
auto register_area_for_square = []() {
area_getters.push_back(area_for_square_getter);
return area_getters.size();
}();
double area_for_square(const Square&) // user defines after this
// declare method
using area_func = double (*)(const Shape*);
using area_func_getter = area_func (*)(const Shape*);
std::vector<area_func_getter> area_getters;
double area(Shape* s) {
for(auto g : area_getters) {
auto func = g();
if(func) return func(s);
}
throw error("Object doesn't implement area");
}
// define method
double area_for_square(const Square&);
double area_for_square_call(const Shape* s) {
auto square = static_cast<const Square*>(s);
return area_for_square(*square);
}
area_func area_for_square_getter(const Shape* s) {
return dynamic_cast<const Square*>(s) ? area_for_square_call : nullptr;
}
auto register_area_for_square = []() {
area_getters.push_back(area_for_square_getter);
return area_getters.size();
}();
double area_for_square(const Square&) // user defines after this
// declare method
using area_func = double (*)(const Shape*);
using area_func_getter = area_func (*)(const Shape*);
std::vector<area_func_getter> area_getters;
double area(Shape* s) {
for(auto g : area_getters) {
auto func = g();
if(func) return func(s);
}
throw error("Object doesn't implement area");
}
// define method
double area_for_square(const Square&);
double area_for_square_call(const Shape* s) {
auto square = static_cast<const Square*>(s);
return area_for_square(*square);
}
area_func area_for_square_getter(const Shape* s) {
return dynamic_cast<const Square*>(s) ? area_for_square_call : nullptr;
}
auto register_area_for_square = []() {
area_getters.push_back(area_for_square_getter);
return area_getters.size();
}();
double area_for_square(const Square&) // user defines after this
// declare method
using area_func = double (*)(const Shape*);
std::unordered_map<std::type_index, area_func> area_getters;
double area(Shape* s) {
auto f = area_getters.find(std::type_index(typeid(*s)));
if (f == area_getters.end()) throw error("Object doesn't implement area");
return f->second(s);
}
// define method
double area_for_square(const Square&);
double area_for_square_call(const Shape* s) {
auto square = static_cast<const Square*>(s);
return area_for_square(*square);
}
auto register_area_for_square = []() {
area_getters[std::type_index(typeid(Square))] = area_for_square_call;
return area_getters.size();
}();
double area_for_square(const Square&) // user defines after this
// declare method
using area_func = double (*)(const Shape*);
std::unordered_map<std::type_index, area_func> area_getters;
double area(Shape* s) {
auto f = area_getters.find(std::type_index(typeid(*s)));
if (f == area_getters.end()) throw error("Object doesn't implement area");
return f->second(s);
}
// define method
double area_for_square(const Square&);
double area_for_square_call(const Shape* s) {
auto square = static_cast<const Square*>(s);
return area_for_square(*square);
}
auto register_area_for_square = []() {
area_getters[std::type_index(typeid(Square))] = area_for_square_call;
return area_getters.size();
}();
double area_for_square(const Square&) // user defines after this
// declare method
using area_func = double (*)(const Shape*);
std::unordered_map<std::type_index, area_func> area_getters;
double area(Shape* s) {
auto f = area_getters.find(std::type_index(typeid(*s)));
if (f == area_getters.end()) throw error("Object doesn't implement area");
return f->second(s);
}
// define method
double area_for_square(const Square&);
double area_for_square_call(const Shape* s) {
auto square = static_cast<const Square*>(s);
return area_for_square(*square);
}
auto register_area_for_square = []() {
area_getters[std::type_index(typeid(Square))] = area_for_square_call;
return area_getters.size();
}();
double area_for_square(const Square&) // user defines after this
// declare method
using area_func = double (*)(const Shape*);
std::unordered_map<std::type_index, area_func> area_getters;
double area(Shape* s) {
auto f = area_getters.find(std::type_index(typeid(*s)));
if (f == area_getters.end()) throw error("Object doesn't implement area");
return f->second(s);
}
// define method
double area_for_square(const Square&);
double area_for_square_call(const Shape* s) {
auto square = static_cast<const Square*>(s);
return area_for_square(*square);
}
auto register_area_for_square = []() {
area_getters[std::type_index(typeid(Square))] = area_for_square_call;
return area_getters.size();
}();
double area_for_square(const Square&) // user defines after this
multi sub collide(Square $s, Square $c) {
collide_square_square($s, $c);
}
multi sub collide(Circle $s, Circle $c) {
collide_circle_circle($s, $c);
}
multi sub collide(Square $s, Circle $c) {
collide_square_circle($s, $c);
}
multi sub collide(Circle $c, Square $s) {
collide_square_circle($s, $c);
}
my $s1 = get_random_shape;
my $s2 = get_random_shape;
say "Collision: " ~ collide($s1, $s2);
struct Shape {
virtual bool collide(const Shape* other) const = 0;
virtual bool collideImpl(const Square*) const = 0;
virtual bool collideImpl(const Circle*) const = 0;
virtual bool collideImpl(const Triangle*) const = 0;
}
struct Square : public Shape {
virtual bool collide(const Shape* other) const override {
return other->collideImpl(this);
}
virtual bool collideImpl(const Square*) const override;
virtual bool collideImpl(const Circle*) const override;
virtual bool collideImpl(const Triangle*) const override;
};
// ...
shared_ptr<Shape> s1 = get_random_shape();
shared_ptr<Shape> s2 = get_random_shape();
cout << "Collision: " << s1->collide(s2.get()) << '\n';
struct Shape {
virtual bool collide(const Shape* other) const = 0;
virtual bool collideImpl(const Square*) const = 0;
virtual bool collideImpl(const Circle*) const = 0;
virtual bool collideImpl(const Triangle*) const = 0;
}
struct Square : public Shape {
virtual bool collide(const Shape* other) const override {
return other->collideImpl(this); /* copy this in every shape */
}
virtual bool collideImpl(const Square*) const override;
virtual bool collideImpl(const Circle*) const override;
virtual bool collideImpl(const Triangle*) const override;
};
// ...
shared_ptr<Shape> s1 = get_random_shape();
shared_ptr<Shape> s2 = get_random_shape();
cout << "Collision: " << s1->collide(s2.get()) << '\n';
struct Shape {
virtual bool collide(const Shape* other) const = 0;
virtual bool collideImpl(const Square*) const = 0;
virtual bool collideImpl(const Circle*) const = 0;
virtual bool collideImpl(const Triangle*) const = 0;
}
struct Square : public Shape {
virtual bool collide(const Shape* other) const override {
return other->collideImpl(this);
}
virtual bool collideImpl(const Square*) const override;
virtual bool collideImpl(const Circle*) const override;
virtual bool collideImpl(const Triangle*) const override;
};
// ...
shared_ptr<Shape> s1 = get_random_shape();
shared_ptr<Shape> s2 = get_random_shape();
cout << "Collision: " << s1->collide(s2.get()) << '\n';
declare_method(bool, collide,
(virtual_<const Shape&> s1, (virtual_<const Shape&> s2));
define_method(bool, collide, (const Square& s, const Circle& c)
{
return collide_square_circle(s, c);
}
define_method(bool, collide, (const Circle& c, const Square& s)
{
return collide_square_circle(s, c);
}
// ...
shared_ptr<Shape> s1 = get_random_shape();
shared_ptr<Shape> s2 = get_random_shape();
cout << "Collision: " << collide(*s1, *s2) << '\n';
struct collide_index {
size_t first;
size_t second;
};
size_t hash(collide_index); // implement as you wish
collide_index circle_square = {
std::type_index(typeid(Circle).hash_code(),
std::type_index(typeid(Square).hash_code(),
};
module FlyingCreature
def move_to(target)
puts can_move_to?(target) ?
"flying to #{target}"
: "can't fly to #{target}"
end
def can_move_to?(target)
true # flying creatures don't care
end
end
module AfraidOfEvens
def can_move_to?(target)
target % 2 != 0
end
end
a = Object.new
a.extend(FlyingCreature)
a.move_to(10) # -> flying to 10
a.extend(AfraidOfEvens)
a.move_to(10) # -> can’t fly to 10
module FlyingCreature
def move_to(target)
puts can_move_to?(target) ?
"flying to #{target}"
: "can't fly to #{target}"
end
def can_move_to?(target)
true # flying creatures don't care
end
end
module AfraidOfEvens
def can_move_to?(target)
target % 2 != 0
end
end
a = Object.new
a.extend(FlyingCreature)
a.move_to(10) # -> flying to 10
a.extend(AfraidOfEvens)
a.move_to(10) # -> can’t fly to 10
module FlyingCreature
def move_to(target)
puts can_move_to?(target) ?
"flying to #{target}"
: "can't fly to #{target}"
end
def can_move_to?(target)
true # flying creatures don't care
end
end
module AfraidOfEvens
def can_move_to?(target)
target % 2 != 0
end
end
a = Object.new
a.extend(FlyingCreature)
a.move_to(10) # -> flying to 10
a.extend(AfraidOfEvens)
a.move_to(10) # -> can’t fly to 10
module FlyingCreature
def move_to(target)
puts can_move_to?(target) ?
"flying to #{target}"
: "can't fly to #{target}"
end
def can_move_to?(target)
true # flying creatures don't care
end
end
module AfraidOfEvens
def can_move_to?(target)
target % 2 != 0
end
end
a = Object.new
a.extend(FlyingCreature)
a.move_to(10) # -> flying to 10
a.extend(AfraidOfEvens)
a.move_to(10) # -> can’t fly to 10
module FlyingCreature
def move_to(target)
puts can_move_to?(target) ?
"flying to #{target}"
: "can't fly to #{target}"
end
def can_move_to?(target)
true # flying creatures don't care
end
end
module AfraidOfEvens
def can_move_to?(target)
target % 2 != 0
end
end
a = Object.new
a.extend(FlyingCreature)
a.move_to(10) # -> flying to 10
a.extend(AfraidOfEvens)
a.move_to(10) # -> can’t fly to 10
module FlyingCreature
def move_to(target)
puts can_move_to?(target) ?
"flying to #{target}"
: "can't fly to #{target}"
end
def can_move_to?(target)
true # flying creatures don't care
end
end
module AfraidOfEvens
def can_move_to?(target)
target % 2 != 0
end
end
a = Object.new
a.extend(FlyingCreature)
a.move_to(10) # -> flying to 10
a.extend(AfraidOfEvens)
a.move_to(10) # -> can’t fly to 10
// ???
struct Object
{
shared_ptr<ICanMoveTo> m_canMoveTo;
shared_ptr<IMoveTo> m_moveTo;
// ... every possible method ever
bool canMoveTo(int target) const {
return m_canMoveTo->call(target);
} // ... every possible method ever (again)
void extend(shared_ptr<Creature> c) {
c->setObject(this);
m_canMoveTo = c;
m_moveTo = c;
}
void extend(shared_ptr<ICanMoveTo> cmt) {
cmt->setObject(this);
m_canMoveTo = cmt;
} // ... every possible extension ever
};
// ... components
// ... virtual inheritence
// ... A LOT OF CODE
Object o;
o.extend(make_shared<FlyingCreature>());
o.moveTo(10); // flying to 10
o.extend(make_shared<AfraidOfEvens>());
o.moveTo(10); // can't fly to 10
DYNAMIX_MESSAGE_1(void, moveTo, int, target);
DYNAMIX_CONST_MESSAGE_1(bool, canMoveTo, int, target);
struct FlyingCreature {
void moveTo(int target) {
cout << (::canMoveTo(dm_this, target) ?
"flying to " : "can't fly to ")
<< target << '\n';
}
bool canMoveTo(int target) const {
return true;
}
}; DYNAMIX_DEFINE_MIXIN(FlyingCreature, moveTo_msg & canMoveTo_msg);
struct AfraidOfEvens {
bool canMoveTo(int target) const {
return target % 2 != 0;
}
}; DYNAMIX_DEFINE_MIXIN(AfraidOfEvens, priority(1, canMoveTo_msg));
int main() {
object o;
mutate(o).add<FlyingCreature>();
moveTo(o, 10); // flying to 10
mutate(o).add<AfraidOfEvens>();
moveTo(o, 10); // can't fly to 10
}
DYNAMIX_MESSAGE_1(void, moveTo, int, target);
DYNAMIX_CONST_MESSAGE_1(bool, canMoveTo, int, target);
struct FlyingCreature {
void moveTo(int target) {
cout << (::canMoveTo(dm_this, target) ?
"flying to " : "can't fly to ")
<< target << '\n';
}
bool canMoveTo(int target) const {
return true;
}
}; DYNAMIX_DEFINE_MIXIN(FlyingCreature, moveTo_msg & canMoveTo_msg);
struct AfraidOfEvens {
bool canMoveTo(int target) const {
return target % 2 != 0;
}
}; DYNAMIX_DEFINE_MIXIN(AfraidOfEvens, priority(1, canMoveTo_msg));
int main() {
object o;
mutate(o).add<FlyingCreature>();
moveTo(o, 10); // flying to 10
mutate(o).add<AfraidOfEvens>();
moveTo(o, 10); // can't fly to 10
}
DYNAMIX_MESSAGE_1(void, moveTo, int, target);
DYNAMIX_CONST_MESSAGE_1(bool, canMoveTo, int, target);
struct FlyingCreature {
void moveTo(int target) {
cout << (::canMoveTo(dm_this, target) ?
"flying to " : "can't fly to ")
<< target << '\n';
}
bool canMoveTo(int target) const {
return true;
}
}; DYNAMIX_DEFINE_MIXIN(FlyingCreature, moveTo_msg & canMoveTo_msg);
struct AfraidOfEvens {
bool canMoveTo(int target) const {
return target % 2 != 0;
}
}; DYNAMIX_DEFINE_MIXIN(AfraidOfEvens, priority(1, canMoveTo_msg));
int main() {
object o;
mutate(o).add<FlyingCreature>();
moveTo(o, 10); // flying to 10
mutate(o).add<AfraidOfEvens>();
moveTo(o, 10); // can't fly to 10
}
DYNAMIX_MESSAGE_1(void, moveTo, int, target);
DYNAMIX_CONST_MESSAGE_1(bool, canMoveTo, int, target);
struct FlyingCreature {
void moveTo(int target) {
cout << (::canMoveTo(dm_this, target) ?
"flying to " : "can't fly to ")
<< target << '\n';
}
bool canMoveTo(int target) const {
return true;
}
}; DYNAMIX_DEFINE_MIXIN(FlyingCreature, moveTo_msg & canMoveTo_msg);
struct AfraidOfEvens {
bool canMoveTo(int target) const {
return target % 2 != 0;
}
}; DYNAMIX_DEFINE_MIXIN(AfraidOfEvens, priority(1, canMoveTo_msg));
int main() {
object o;
mutate(o).add<FlyingCreature>();
moveTo(o, 10); // flying to 10
mutate(o).add<AfraidOfEvens>();
moveTo(o, 10); // can't fly to 10
}
DYNAMIX_MESSAGE_1(void, moveTo, int, target);
DYNAMIX_CONST_MESSAGE_1(bool, canMoveTo, int, target);
struct FlyingCreature {
void moveTo(int target) {
cout << (::canMoveTo(dm_this, target) ?
"flying to " : "can't fly to ")
<< target << '\n';
}
bool canMoveTo(int target) const {
return true;
}
}; DYNAMIX_DEFINE_MIXIN(FlyingCreature, moveTo_msg & canMoveTo_msg);
struct AfraidOfEvens {
bool canMoveTo(int target) const {
return target % 2 != 0;
}
}; DYNAMIX_DEFINE_MIXIN(AfraidOfEvens, priority(1, canMoveTo_msg));
int main() {
object o;
mutate(o).add<FlyingCreature>();
moveTo(o, 10); // flying to 10
mutate(o).add<AfraidOfEvens>();
moveTo(o, 10); // can't fly to 10
}
DYNAMIX_MESSAGE_1(void, moveTo, int, target);
DYNAMIX_CONST_MESSAGE_1(bool, canMoveTo, int, target);
struct FlyingCreature {
void moveTo(int target) {
cout << (::canMoveTo(dm_this, target) ?
"flying to " : "can't fly to ")
<< target << '\n';
}
bool canMoveTo(int target) const {
return true;
}
}; DYNAMIX_DEFINE_MIXIN(FlyingCreature, moveTo_msg & canMoveTo_msg);
struct AfraidOfEvens {
bool canMoveTo(int target) const {
return target % 2 != 0;
}
}; DYNAMIX_DEFINE_MIXIN(AfraidOfEvens, priority(1, canMoveTo_msg));
int main() {
object o;
mutate(o).add<FlyingCreature>();
moveTo(o, 10); // flying to 10
mutate(o).add<AfraidOfEvens>();
moveTo(o, 10); // can't fly to 10
}
MixQuest: github.com/iboB/mixquest
// message_registry
struct message_info {}
std::vector<message_info*> msg_infos;
// register mixin
auto moveTo_id = []() {
msg_infos.emplace_back();
return msg_infos.size();
}();
template <typename Mixin>
void* moveTo_caller() {
return [](void* mixin, int target) {
auto m = reintepret_cast<Mixin*>(mixin);
m->moveTo(target);
};
}
void moveTo(object& o, int target);
// message_registry
struct message_info {}
std::vector<message_info*> msg_infos;
// register mixin
auto moveTo_id = []() {
msg_infos.emplace_back();
return msg_infos.size();
}();
template <typename Mixin>
void* moveTo_caller() {
return [](void* mixin, int target) {
auto m = reintepret_cast<Mixin*>(mixin);
m->moveTo(target);
};
}
void moveTo(object& o, int target);
// message_registry
struct message_info {}
std::vector<message_info*> msg_infos;
// register mixin
auto moveTo_id = []() {
msg_infos.emplace_back();
return msg_infos.size();
}();
template <typename Mixin>
void* moveTo_caller() {
return [](void* mixin, int target) {
auto m = reintepret_cast<Mixin*>(mixin);
m->moveTo(target);
};
}
void moveTo(object& o, int target);
// message_registry
struct message_info {}
std::vector<message_info*> msg_infos;
// register mixin
auto moveTo_id = []() {
msg_infos.emplace_back();
return msg_infos.size();
}();
template <typename Mixin>
void* moveTo_caller() {
return [](void* mixin, int target) {
auto m = reintepret_cast<Mixin*>(mixin);
m->moveTo(target);
};
}
void moveTo(object& o, int target);
// mixin_registry
struct mixin_info {
std::vector<void*> funcs;
}
std::vector<mixin_info*> mixin_infos;
// register mixin
auto FlyingCreature_id = []() {
auto info = new mixin_type_info;
info->funcs.resize(registered_messages.size());
info->funcs[moveTo_id] = moveTo_caller<FlyingCreature>
}();
mixin_type_info* info_for(FlyingCreature*) {
return mixin_infos[FlyingCreature_id];
}
// mixin_registry
struct mixin_info {
std::vector<void*> funcs;
}
std::vector<mixin_info*> mixin_infos;
// register mixin
auto FlyingCreature_id = []() {
auto info = new mixin_type_info;
info->funcs.resize(registered_messages.size());
info->funcs[moveTo_id] = moveTo_caller<FlyingCreature>
}();
mixin_type_info* info_for(FlyingCreature*) {
return mixin_infos[FlyingCreature_id];
}
// mixin_registry
struct mixin_info {
std::vector<void*> funcs;
}
std::vector<mixin_info*> mixin_infos;
// register mixin
auto FlyingCreature_id = []() {
auto info = new mixin_type_info;
info->funcs.resize(registered_messages.size());
info->funcs[moveTo_id] = moveTo_caller<FlyingCreature>
}();
mixin_type_info* info_for(FlyingCreature*) {
return mixin_infos[FlyingCreature_id];
}
struct object {
vector<std::unique_ptr<void>> mixins;
struct vtable_entry {
void* mixin;
void* caller;
};
vector<vtable_entry> vtable;
template <typename Mixin>
void add() {
mixins.emplace_back(make_unique<Mixin>());
auto info = info_for((Mixin*)nullptr);
for(size_t i=0; i<registered_messages.size(); ++i) {
if (info->funcs[i]) vtable[i] =
{mixins.back().get(), info->funcs[i]};
}
}
};
struct object {
vector<std::unique_ptr<void>> mixins;
struct vtable_entry {
void* mixin;
void* caller;
};
vector<vtable_entry> vtable;
template <typename Mixin>
void add() {
mixins.emplace_back(make_unique<Mixin>());
auto info = info_for((Mixin*)nullptr);
for(size_t i=0; i<registered_messages.size(); ++i) {
if (info->funcs[i]) vtable[i] =
{mixins.back().get(), info->funcs[i]};
}
}
};
struct object {
vector<std::unique_ptr<void>> mixins;
struct vtable_entry {
void* mixin;
void* caller;
};
vector<vtable_entry> vtable;
template <typename Mixin>
void add() {
mixins.emplace_back(make_unique<Mixin>());
auto info = info_for((Mixin*)nullptr);
for(size_t i=0; i<registered_messages.size(); ++i) {
if (info->funcs[i]) vtable[i] =
{mixins.back().get(), info->funcs[i]};
}
}
};
struct object {
vector<std::unique_ptr<void>> mixins;
struct vtable_entry {
void* mixin;
void* caller;
};
vector<vtable_entry> vtable;
template <typename Mixin>
void add() {
mixins.emplace_back(make_unique<Mixin>());
auto info = info_for((Mixin*)nullptr);
for(size_t i=0; i<registered_messages.size(); ++i) {
if (info->funcs[i]) vtable[i] =
{mixins.back().get(), info->funcs[i]};
}
}
};
struct object {
vector<std::unique_ptr<void>> mixins;
struct vtable_entry {
void* mixin;
void* caller;
};
vector<vtable_entry> vtable;
template <typename Mixin>
void add() {
mixins.emplace_back(make_unique<Mixin>());
auto info = info_for((Mixin*)nullptr);
for(size_t i=0; i<registered_messages.size(); ++i) {
if (info->funcs[i]) vtable[i] =
{mixins.back().get(), info->funcs[i]};
}
}
};
void moveTo(object& o, int target) {
auto& entry = o.vtable[moveTo_id];
auto caller = reintepret_cast<void(*)(void*, int)>(entry.caller);
caller(entry.mixin, target);
}
The beast is back! - Jon Kalb
Borislav Stanimirov / ibob.github.io / @stanimirovb
Link to these slides: http://ibob.github.io/slides/oop-in-cpp/
Slides license Creative Commons By 3.0