How to do multiple inheritance just for function?
Here are similar questions :-
Here is a sample code (coliru demo) :-
class O{
protected: int database=0;
};
class A : public O{
public: void print(){
std::cout<<database<<std::endl;
}
};
class B : public O{
public: void set(int s){
database=s+1;
}
};
class AB : public O{
public: void print(){//duplicate
std::cout<<database<<std::endl;
}
public: void set(int s){//duplicate
database=s+1;
}
};
//AB ab; ab.set(1); ab.print(); // would print 2
Here is my attempt (wandbox demo). I abuse CRTP :(
:-
class O{
public: int database=0;
};
template<class T>class OA{
public: void print(){
std::cout<<static_cast<T*>(this)->database<<std::endl;
}
};
template<class T>class OB{
public: void set(int s){
static_cast<T*>(this)->database=s+1;
}
};
class A :public O,public OA<A>{};
class B :public O,public OB<B>{};
class AB :public O,public OA<AB>,public OB<AB>{};
It works, but it looks inelegant.
Furthermore, implementation must be in header (because OA
and OB
are template classes).
Are there better approaches? Or is this the way to go?
Sorry if it is too newbie question or already asked. I am a C++ beginner.
Give extended example of using please.
In ECS, it would be useful in some cases :-
class O{
protected: EntityHandle e;
};
class ViewAsPhysic : public O{ //A
public: void setTransform(Transformation t){
Ptr<PhysicTransformComponent> g=e;
g->transform=t;
}
};
class ViewAsLight : public O{ //B
public: void setBrightness(int t){
Ptr<LightComponent> g=e;
g->clan=t;
}
};
class ViewAsLightBlock : public O{ //AB
//both functions
};
The problem here is that the database
field is member of class O. So without virtual inheritance, A and B will have each their own copy of database
. So you must find a way to force A and B to share same value. You could for example use a reference field initialized in a protected constructor:
#include <iostream>
class O{
int _db;
protected: int &database;
O(): database(_db) {};
O(int &db): database(db) {};
};
class A : public O{
public: void print(){
std::cout<<database<<std::endl;
}
A() {} // public default ctor
protected: A(int& db): O(db) {}; // protectect ctor
};
class B : public O{
public: void set(int s){
database=s+1;
}
B() {} // public default ctor
protected: B(int& db): O(db) {}; // protectect ctor
};
class AB : public A, public B {
int _db2;
public: AB(): A(_db2), B(_db2) {}; // initialize both references to same private var
};
int main() {
AB ab;
ab.set(1);
ab.print();
return 0;
}
displays as expected:
2
Above code uses no virtual inheritance, no virtual function and no templates, so method can safely implemented in cpp files. The class AB actually uses methods from its both parents and has still a coherent view on its underlying data. In fact it simulates an explicit virtual inheritance by building the common data in the most derived class and injecting in through protected constructors in its parents.