I am trying to use interface IComparable (not in this mockup code) and its 2 implementations to work on same object.
I must use operators to do so.
I would like to do it without resolving like here c.right::operator--().
Here I have interfaces Common and Uni both inherited by Inter. Then I have right and left that blend into custom class implementing both Common and 2 versions of Uni interfaces.
2 different versions meaning one that uses operator to call f() and the other to call g().
#include<iostream>
class Common {
public:
Common() { std::cout << "common\n"; }
};
class Uni {
public:
Uni() { std::cout << "uni\n"; }
virtual void operator--() = 0;
};
class Inter : virtual public Common, public Uni {
public:
Inter() { std::cout << "inter\n"; }
};
class left : public Inter {
public:
left() { std::cout << "left\n"; }
void operator--() override { f(); }
virtual void f() = 0;
};
class right : public Inter {
public:
right() { std::cout << "right\n"; }
void operator--() override { g(); }
virtual void g() = 0;
};
class custom : public right, public left {
public:
custom() { std::cout << "custom\n"; }
void f() override { std::cout << "lol\n"; }
void g() override { std::cout << "gfunc\n"; }
};
class custom2 : public right, public left {
public:
custom2() { std::cout << "custom2\n"; }
void f() override { std::cout << "lol2\n"; }
void g() override { std::cout << "gfunc2\n"; }
};
int main()
{
custom c;
custom2 c2;
c.left::operator--();
c.right::operator--();
c2.right::operator--();
}
Related
I am trying to organize public member function in groups and sub groups. But I would like these functions to have access to all public and private members of the class. Here is a code that does the job, but it is ugly. I am looking for more elegant way of doing the same thing.
#include "iostream"
class tClass
{
public:
tClass()
{
this->Grp1.SubGrp1.me = this;
this->Grp1.SubGrp2.me = this;
this->Grp1.SubGrp3.me = this;
};
~tClass() {};
struct Grp1
{
struct SubGrp1
{
tClass* me;
void Fun1(void) { me->Group1_SubGroup1_Function1(); };
void Fun2(void) { me->Group1_SubGroup1_Function2(); };
void Fun3(void) { me->Group1_SubGroup1_Function3(); };
}SubGrp1;
struct SubGrp2
{
tClass* me;
void Fun1(void) { me->Group1_SubGroup2_Function1(); };
void Fun2(void) { me->Group1_SubGroup2_Function2(); };
}SubGrp2;
struct SubGrp3
{
tClass* me;
void Fun1(void) { me->Group1_SubGroup3_Function1(); };
}SubGrp3;
}Grp1;
private:
void Group1_SubGroup1_Function1(void) { std::cout << "Group1_SubGroup1_Function1\n"; };
void Group1_SubGroup1_Function2(void) { std::cout << "Group1_SubGroup1_Function2\n"; };
void Group1_SubGroup1_Function3(void) { std::cout << "Group1_SubGroup1_Function3\n"; };
void Group1_SubGroup2_Function1(void) { std::cout << "Group1_SubGroup2_Function1\n"; };
void Group1_SubGroup2_Function2(void) { std::cout << "Group1_SubGroup2_Function2\n"; };
void Group1_SubGroup3_Function1(void) { std::cout << "Group1_SubGroup3_Function1\n"; };
};
int main()
{
tClass aClass;
aClass.Grp1.SubGrp1.Fun1();
aClass.Grp1.SubGrp1.Fun2();
aClass.Grp1.SubGrp1.Fun3();
aClass.Grp1.SubGrp2.Fun1();
aClass.Grp1.SubGrp2.Fun2();
aClass.Grp1.SubGrp3.Fun1();
}
This is an IDE feature, not a C++ one.
For example visual studio allows for this (might not work in other environments). This allows you to group without impacting source code.
Bonus you can collapse groups to one line and expand them later.
#pragma region my_group_1
#pragma region sub_group_1
void func1();
#pragma endregion
#pragma region sub_group_2
void func2();
#pragma endregion
#pragma endregion
Mnd, this is how would organize your code example :
#include <iostream>
#include <string>
//------------------------------------------------------------------------------
// a base class to get all the constructors/destructors setup
// for an abstract base class ("interface")
struct interface_t
{
public:
interface_t(const interface_t&) = delete;
interface_t& operator=(const interface_t&) = delete;
interface_t(interface_t&&) = delete;
protected:
interface_t() = default;
virtual ~interface_t() = default;
};
//------------------------------------------------------------------------------
// now setup interfaces for all your groups
class group1_subgroup1_itf :
public interface_t
{
public:
virtual void fun1() = 0;
virtual void fun2() = 0;
};
class group1_subgroup2_itf :
public interface_t
{
public:
virtual void fun3() = 0;
virtual void fun4() = 0;
};
class group1_itf :
public interface_t
{
public:
virtual group1_subgroup1_itf& sub1() = 0;
virtual group1_subgroup2_itf& sub2() = 0;
};
class t_class_itf :
public interface_t
{
public:
virtual group1_itf& group1() = 0;
};
//------------------------------------------------------------------------------
// Then put your implementation all in one class, just like normal.
// let this class implement all the interfaces (groupings)
//
namespace impl
{
class t_class :
public t_class_itf,
public group1_itf,
public group1_subgroup1_itf,
public group1_subgroup2_itf
{
public:
explicit t_class(const std::string name) :
m_name{ name }
{
};
virtual ~t_class() override = default;
// todo other constructors
// implementation of navigation functions, they all end up in the same implementation.
virtual group1_itf& group1() override {return dynamic_cast<group1_itf&>(*this); }
virtual group1_subgroup1_itf& sub1() override { return dynamic_cast<group1_subgroup1_itf&>(*this); }
virtual group1_subgroup2_itf& sub2() override { return dynamic_cast<group1_subgroup2_itf&>(*this); }
// implementations
virtual void fun1() override { std::cout << m_name << "::fun1" << std::endl; }
virtual void fun2() override { std::cout << m_name << "::fun2" << std::endl; }
virtual void fun3() override { std::cout << m_name << "::fun3" << std::endl; }
virtual void fun4() override { std::cout << m_name << "::fun4" << std::endl; }
private:
std::string m_name;
};
} /* namespace impl */
//------------------------------------------------------------------------------
// client facing class
// used for "navigation" only
//
class t_class :
public t_class_itf
{
public:
explicit t_class(const std::string& name) :
m_impl{ name }
{
};
virtual group1_itf& group1() override { return dynamic_cast<group1_itf&>(m_impl); }
private:
impl::t_class m_impl;
};
//------------------------------------------------------------------------------
// and then its use.
int main()
{
t_class t{"t_class"};
t.group1().sub1().fun1();
t.group1().sub2().fun4();
return 0;
}
Thanks to all commends I got ideas how to decrease the complexity.
Here is simple solution and better example that exercises public/private access rights.
Memory Overhead: Extra pointer in each subgroup.
Code Overhead: Dynamic Initialization of all subgroup pointers.
#include "iostream"
class tClass
{
public:
tClass()
{
this->Grp1.SubGrp1.me = this;
this->Grp1.SubGrp2.me = this;
this->Grp1.SubGrp3.me = this;
};
~tClass() {};
struct Grp1
{
struct SubGrp1
{
tClass* me;
void Fun1(void) { me->aVar = 0x0101; me->mCount++; std::cout << "Group1_SubGroup1_Function1 Count=" << me->mCount << "\n"; };
void Fun2(void) { me->aVar = 0x0102; me->mCount++; std::cout << "Group1_SubGroup1_Function2 Count=" << me->mCount << "\n"; };
void Fun3(void) { me->aVar = 0x0103; me->mCount++; std::cout << "Group1_SubGroup1_Function3 Count=" << me->mCount << "\n"; };
}SubGrp1;
struct SubGrp2
{
tClass* me;
void Fun1(void) { me->aVar = 0x0201; me->mCount++; std::cout << "Group1_SubGroup2_Function1 Count=" << me->mCount << "\n"; };
void Fun2(void) { me->aVar = 0x0201; me->mCount++; std::cout << "Group1_SubGroup2_Function2 Count=" << me->mCount << "\n"; };
}SubGrp2;
struct SubGrp3
{
tClass* me;
void Fun1(void) { me->aVar = 0x0301; me->mCount++; std::cout << "Group1_SubGroup3_Function1 Count=" << me->mCount << "\n"; };
}SubGrp3;
}Grp1;
unsigned int aVar = 0x0000;
private:
int mCount = 0;
};
int main()
{
tClass aClass;
aClass.Grp1.SubGrp1.Fun1();
aClass.Grp1.SubGrp1.Fun2();
aClass.Grp1.SubGrp1.Fun3();
aClass.Grp1.SubGrp2.Fun1();
aClass.Grp1.SubGrp2.Fun2();
aClass.Grp1.SubGrp3.Fun1();
}
I would like to have a child class Handler that handles multiple callbacks and transfers data from one class to another. However, the base classes B1 and B2can have different implementations for its members.
Below a way to implement the behavior I want. I think there should be a better way but cannot figure it out.
// Example program
#include <iostream>
#include <string>
template <class T>
class IBase
{
public:
IBase()
{
object = new T(*this);
};
~IBase()
{
delete object;
}
virtual void ValidateCallback()
{
};
void RxCallback()
{
object->RxCallback();
};
void Send()
{
object->Send();
};
T* object;
};
class C1
{
public:
virtual void RxCompleteCallback() = 0;
void RxParse()
{
std::cout << "Parse C1" << std::endl;
RxCompleteCallback();
};
};
class C2
{
public:
virtual void RxCompleteCallback() = 0;
void RxParse()
{
std::cout << "Parse C2" << std::endl;
RxCompleteCallback();
};
};
class B1 : public C1
{
public:
B1(IBase<B1> &handler )
{
ihandler = &handler;
};
void DoSomething()
{
std::cout << "DoSomething B1" << std::endl;
ihandler->ValidateCallback();
};
void RxCompleteCallback() override
{
std::cout << "DoSomething other than B2" << std::endl;
std::cout << "RxCompleteCallback" << std::endl;
};
void RxCallback()
{
RxParse();
};
void Send()
{
DoSomething();
};
IBase<B1> * ihandler;
};
class B2 : public C2
{
public:
B2(IBase<B2> &handler )
{
ihandler = &handler;
};
void DoSomething()
{
std::cout << "DoSomething B2" << std::endl;
ihandler->ValidateCallback();
};
void RxCompleteCallback() override
{
std::cout << "DoSomething other than B1" << std::endl;
std::cout << "RxCompleteCallback" << std::endl;
};
void RxCallback()
{
RxParse();
};
void Send()
{
DoSomething();
};
IBase<B2> * ihandler;
};
class Validate
{
public:
void CalculateValidation()
{
std::cout << "Calculate validation" << std::endl;
};
};
template <class T>
class Handler : public IBase<T>, public Validate
{
public:
void ValidateCallback() override
{
std::cout << "ValidateCallback" << std::endl;
CalculateValidation();
};
void Receive()
{
IBase<T>::RxCallback();
};
void Send()
{
IBase<T>::Send();
}
};
int main()
{
Handler<B1> handler1;
handler1.Receive();
handler1.Send();
std::cout << std::endl;
Handler<B2> handler2;
handler2.Receive();
handler2.Send();
}
Output:
Parse C1
DoSomething other than B2
RxCompleteCallback
DoSomething B1
ValidateCallback
Calculate validation
Parse C2
DoSomething other than B1
RxCompleteCallback
DoSomething B2
ValidateCallback
Calculate validation
There are several ways to do this in C++. It's hard to say what the best way is, it depends on how you will use it, and the example you gave is too simple to recommend a specific way. Normally, I'd say you want to derive your protocol-specific classes from Handler, instead of the other way around, so you'd write:
class Handler {
public:
virtual void Receive() {};
virtual void Send() {};
};
class B1: public Handler {
virtual void Receive() {
...
}
virtual void Send() {
...
}
};
int main() {
B1 handler1;
handler1.Receive();
...
}
The main issue here is that you need to use virtual member functions here, otherwise the base class doesn't know which derived class's implementation to call. But it does allow you to pass a Handler * as an argument to another function, which will then work with any derived class without needing any templating.
Another option is to use the curiously recurring template pattern, which would look like:
template <typename T>
class Handler {
void Receive() {
static_cast<T*>(this)->Receive();
}
void Send() {
static_cast<T*>(this)->Send();
}
};
class B1: public Handler<B1>
{
void Receive() {
...
}
void Send() {
...
}
};
int main() {
B1 handler1;
handler1.Receive();
...
}
This avoids virtual methods.
It is also quite similar to your class Handler, but it has the advantage that it doesn't need the T *object member variable.
I have two classes B andY which I cannot change or edit by requirement. They have functions doing the same thing but with different names.
I want to a have a common interfaces with selecting the class at run time depending on the some input variable as described in the code below. I am not sure which design pattern should I use. How to create WrapperYB class which selects Y::show or B::showing depending on the object created.
class A
{
public:
A() {}
virtual ~A();
virtual void show() { cout << "show A" << endl;}
};
class B:A
{
public:
B() {}
virtual ~B();
virtual void show() { cout << "show B" << endl;}
};
class X
{
char m_i;
public:
Y() { m_i = 'X';}
virtual void showing() { cout << "showing " << m_i << endl;}
};
class Y:X
{
public:
Y() { m_i = 'Y';}
virtual void showing() { cout << "showing " << m_i << endl;}
};
class WrapperYB
{
// to be implemented
public:
explicit WrapperYB(const int& type);
void show();
};
int main(){
WrapperYB objY(1);
objY.show(); // must call Y::showing
WrapperYB objB(0);
objB.show(); // must call B::show
}
If your compiler supports the C++17 Standard, you could try this solution using std::variant. This is a similar idea to the solution in #Nicolas's answer, but variant will take care of the implementation details for you, won't use dynamic memory allocation, and has support for additional things like copy and assignment.
#include <variant>
#include <utility>
#include <type_traits>
class WrapperYB {
public:
using variant_type = std::variant<Y, B>;
template <typename... Args,
std::enable_if_t<std::is_constructible_v<variant_type, Args...>>* = nullptr>
WrapperYB(Args&& ... args) : m_variant(std::forward<Args>(args)...) {}
variant_type& variant() noexcept { return m_variant; }
const variant_type& variant() const noexcept { return m_variant; }
void show()
{ std::visit(ShowImpl{}, m_variant); }
private:
struct ShowImpl {
void operator() (Y& y) const { y.showing(); }
void operator() (B& b) const { b.show(); }
};
variant_type m_variant;
};
See the full working example on coliru.
You might generalize the wrapper by letting it contain a std::unique_ptr<A> or std::unique_ptr<X> instead.
I'm proposing this:
#include <iostream>
using namespace std;
class A
{
public:
A() {}
virtual ~A() {}
virtual void show() { cout << "show A" << endl;}
};
class B:A
{
public:
B() {}
virtual ~B() {}
virtual void show() { cout << "show B" << endl;}
};
class X
{
protected:
char m_i;
public:
X () { m_i = 'X';}
virtual void showing() { cout << "showing " << m_i << endl;}
};
class Y:X
{
public:
Y() { m_i = 'Y';}
virtual void showing() { cout << "showing " << m_i << endl;}
};
class WrapperYB
{
public:
enum class Which { B, Y };
public:
explicit WrapperYB (int n)
: which(Which(n))
{
switch (which)
{
case Which::B: ptr.b = new B; break;
case Which::Y: ptr.y = new Y; break;
}
}
~WrapperYB ()
{
switch (which)
{
case Which::B: delete ptr.b; break;
case Which::Y: delete ptr.y; break;
}
}
WrapperYB (const WrapperYB&) = delete;
WrapperYB& operator = (const WrapperYB&) = delete;
public:
void show()
{
switch (which)
{
case Which::B: ptr.b->show() ; break;
case Which::Y: ptr.y->showing(); break;
}
}
private:
Which which;
union {
Y* y;
B* b;
} ptr;
};
int main(){
WrapperYB objY(1);
objY.show(); // must call Y::showing
WrapperYB objB(0);
objB.show(); // must call B::show
}
It's not a "Vanilla" design pattern, I don't think, and more of combination of adapter and discriminated union.
Note that WrapperYB cannot be copied or assigned, as is.
You can use a standard virtual dispatch method with an abstract base adaptor class and subclasses for each object type needed. Create the object with a factory method.
#include <memory>
//pre-defined structures Y, B
struct Y
{
Y(){}
~Y(){}
void show(){}
};
struct B
{
B(){}
~B(){}
void showing(){}
};
// Abstract adaptor base class.
struct Adaptor
{
virtual void show() = 0;
};
// A subclass of Adaptor for each type of object to be wrapped.
struct Adaptor_Y: Adaptor
{
Adaptor_Y(): y(){}
void show() override
{
y.show();
}
private:
Y y;
};
struct Adaptor_B: Adaptor
{
Adaptor_B(): b(){}
void show() override
{
b.showing();
}
private:
B b;
};
// Factory method constructs the proper object and returns a pointer.
std::unique_ptr<Adaptor> get_adaptor(int flag)
{
if(flag == 0)
{
return std::make_unique<Adaptor_B>();
}
else if(flag == 1)
{
return std::make_unique<Adaptor_Y>();
}
else throw std::runtime_error("Invalid flag value");
}
I have been looking for a way to use both templating and polymorphism at the same time. Here's a simplified version of my problem:
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
//*******************************************************************
//*******************************************************************
struct DerivedStuff1
{
static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2
{
static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
template<typename StuffType> virtual void eval() const = 0;
};
class DerivedClass1 : public BaseClass
{
public:
template<typename StuffType> virtual void eval() const
{
std::cout << "We are in DerivedClass1: ";
StuffType::eval();
}
};
class DerivedClass2 : public BaseClass
{
public:
template<typename StuffType> virtual void eval() const
{
std::cout << "We are in DerivedClass2: ";
StuffType::eval();
}
};
int main()
{
BaseClass* c1 = new DerivedClass1;
c1->eval<DerivedStuff1>();
c1->eval<DerivedStuff2>();
BaseClass* c2 = new DerivedClass2;
c2->eval<DerivedStuff1>();
c2->eval<DerivedStuff2>();
return 0;
}
This code does not compile because virtual template functions are not allowed in C++. I found a few approaches to tackle this problem (CRTP, etc.) but none of them were really satisfying. Is there no elegant way to get around that issue?
The visitor pattern turns run-time polymorphism on its side and makes runtime-polymorphic function templates possible. It has other legitimate uses apart from templatisation, so I guess you can call it somewhat elegant.
Your example can look as follows:
#include <iostream>
class DerivedStuff1 {
public:
static void eval() { std::cout << "Evaluating DerivedStuff1\n"; }
};
class DerivedStuff2 {
public:
static void eval() { std::cout << "Evaluating DerivedStuff2\n"; }
};
class DerivedClass1; class DerivedClass2;
class BaseClassVisitor {
public:
virtual void visit(DerivedClass1&) = 0;
virtual void visit(DerivedClass2&) = 0;
};
class BaseClass {
public:
virtual void accept(BaseClassVisitor& v) = 0;
};
class DerivedClass1 : public BaseClass
{
public:
virtual void accept(BaseClassVisitor& v) { v.visit(*this); }
};
class DerivedClass2 : public BaseClass
{
public:
virtual void accept(BaseClassVisitor& v) { v.visit(*this); }
};
template <typename StuffType>
class EvalVisitor : public BaseClassVisitor
{
virtual void visit(DerivedClass1&) {
std::cout << "We are in DerivedClass1: ";
StuffType::eval();
}
virtual void visit(DerivedClass2&) {
std::cout << "We are in DerivedClass2: ";
StuffType::eval();
}
};
int main()
{
EvalVisitor<DerivedStuff1> e1;
EvalVisitor<DerivedStuff2> e2;
BaseClass* c1 = new DerivedClass1;
c1->accept(e1);
c1->accept(e2);
BaseClass* c2 = new DerivedClass2;
c2->accept(e1);
c2->accept(e2);
return 0;
}
Demo
Of course all shortcomings of Visitor apply here.
You could reinvent the vtable and resolve the function pointer at run time. You will, however, have to explicitely instantiate the template on the derived class, but I don't see any approach to this that won't require that.
Quick and dirty example:
#include <map>
#include <iostream>
class Base {
public:
typedef void (Base::*eval_ptr)();
using eval_vtable = std::map<std::type_index, eval_ptr>;
Base(eval_vtable const& eval_p) : eval_ptrs(eval_p) {}
template<typename T>
void eval() {
auto handler = eval_ptrs.find(type_index(typeid(T)));
if(handler != eval_ptrs.end()) {
auto handler_ptr = handler->second;
(this->*handler_ptr)();
}
}
eval_vtable const& eval_ptrs;
};
class Derived : public Base {
public:
Derived()
: Base(eval_functions) {}
template<typename T>
void eval_impl() {
std::cout << typeid(T).name() << "\n";
}
static eval_vtable eval_functions;
};
Base::eval_vtable Derived::eval_functions = {
{ type_index(typeid(int)), eval_ptr(&Derived::eval_impl<int>) },
{ type_index(typeid(float)), eval_ptr(&Derived::eval_impl<float>) },
{ type_index(typeid(short)), eval_ptr(&Derived::eval_impl<short>) },
};
int main(int argc, const char* argv[]) {
Derived x;
Base * x_as_base = &x;
x_as_base->eval<int>(); // calls Derived::eval_impl<int>()
return 0;
}
This won't be exactly fast, but it will give you the closest thing to templated virtual functions that I can think of.
Edit: For the record I don't advocate anyone use this. I would much rather revisit the design to avoid being painted in this particular corner in the first place. Please consider my answer as an academic solution to a theoretical problem, not an actual engineering recommendation.
Since virtual template methods in C++ arent allowed, you can make a class template and call static function of class template param.
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
//*******************************************************************
//*******************************************************************
struct DerivedStuff1
{
static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2
{
static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
virtual void eval() const = 0;
};
template<typename StuffType>
class DerivedClass1 : public BaseClass
{
public:
virtual void eval() const
{
std::cout << "We are in DerivedClass1: ";
StuffType::eval();
}
};
template<typename StuffType>
class DerivedClass2 : public BaseClass
{
public:
virtual void eval() const
{
std::cout << "We are in DerivedClass2: ";
StuffType::eval();
}
};
int main()
{
BaseClass* c1 = new DerivedClass1<DerivedStuff1>;
c1->eval();
c1 = new DerivedClass1<DerivedStuff2>;
c1->eval();
BaseClass* c2 = new DerivedClass2<DerivedStuff1>;
c2->eval();
c2 = new DerivedClass2<DerivedStuff2>;
c2->eval();
// deletes
return 0;
}
Output
We are in DerivedClass1: evaluating DerivedStuff1
We are in DerivedClass1: evaluating DerivedStuff2
We are in DerivedClass2: evaluating DerivedStuff1
We are in DerivedClass2: evaluating DerivedStuff2
You cannot mix templates (compile time) and polymorphic (runtime). That's it.
So, a posible workaround is remove templates. For example, it could take a function pointer or just more polymorphism:
//*******************************************************************
//*******************************************************************
struct InterfaceStuff{
virtual void eval() = 0;
}
struct DerivedStuff1 : public InterfaceStuff
{
void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2 : public InterfaceStuff
{
void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
virtual void eval(InterfaceStuff* interface) const = 0;
};
class DerivedClass1 : public BaseClass
{
public:
virtual void eval(InterfaceStuff* interface) const
{
std::cout << "We are in DerivedClass1: ";
interface->eval();
}
};
class DerivedClass2 : public BaseClass
{
public:
virtual void eval(InterfaceStuff* interface) const
{
std::cout << "We are in DerivedClass2: ";
interface->eval();
}
};
Another posible workaround is remove polymorphism, just use more templates:
struct DerivedStuff1
{
static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2
{
static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
template<typename Eval,typename StuffType> void eval() const
{
Eval::eval();
StuffType::eval();
}
};
class DerivedClass1 : public BaseClass
{
};
class DerivedClass2 : public BaseClass
{
};
One way of another, you have to choose one.
If we have diamond inheritance and use public virtual base classes, we can stop the first constructor from being called multiple times. Now, I'd like to do the same sort of thing for functions outside of the constructor. For example, the code:
#include <iostream>
struct A {
virtual void foo() {
std::cout << "A" << std::endl;
}
};
struct B : virtual public A {
virtual void foo() {
A::foo();
std::cout << "B" << std::endl;
}
};
struct C : virtual public A {
virtual void foo() {
A::foo();
std::cout << "C" << std::endl;
}
};
struct D : public B, public C{
virtual void foo() {
B::foo();
C::foo();
std::cout << "D" << std::endl;
}
};
int main() {
D d;
d.foo();
}
produces the result
A
B
A
C
D
I'd like to modify it so that it just produces
A
B
C
D
What sort of strategies or patterns accomplish this?
EDIT 1
I like Tony D's answer better than the following. Nonetheless, it's in theory possible to use constructors of another class in order to define the proper hierarchy of functions. Specifically
#include <iostream>
struct A;
struct B;
struct C;
struct D;
namespace foo {
struct A {
A(::A* self);
};
struct B : virtual public A {
B(::B* self);
};
struct C : virtual public A {
C(::C* self);
};
struct D : public B, public C{
D(::D* self);
};
}
struct A {
private:
friend class foo::A;
friend class foo::B;
friend class foo::C;
friend class foo::D;
int data;
public:
A() : data(0) {}
virtual void foo() {
(foo::A(this));
}
void printme() {
std::cout << data << std::endl;
}
};
struct B : virtual public A {
virtual void foo() {
(foo::B(this));
}
};
struct C : virtual public A {
virtual void foo() {
(foo::C(this));
}
};
struct D : public B, public C{
virtual void foo() {
(foo::D(this));
}
};
foo::A::A(::A* self) {
self->data+=1;
std::cout << "A" << std::endl;
}
foo::B::B(::B* self) : A(self) {
self->data+=2;
std::cout << "B" << std::endl;
}
foo::C::C(::C* self) : A(self) {
self->data+=4;
std::cout << "C" << std::endl;
}
foo::D::D(::D* self) : A(self), B(self), C(self) {
self->data+=8;
std::cout << "D" << std::endl;
}
int main() {
D d;
d.foo();
d.printme();
}
Basically, the classes inside of the namespace foo do the computation for the function named foo. This seems a little verbose, so perhaps there's a better way to do it.
EDIT 2
Thanks again to Tony D for clarifying the above example. Yes, essentially what the above does is create temporary variables that adhere to the virtual base designation. In this way, we can use the constructor in order to prevent redundant computations. The extra cruft was to try and show how to get access to access to private members that may have been buried in the base class. Thinking about it a little bit more, there's another way to do this, which may or may not be cleaner depending on the application. I'll leave it here for reference. As with the last example, the weakness is that we're essentially required to wire the the inheritance again, by hand.
#include <iostream>
struct A {
protected:
int data;
public:
A() : data(0) {}
struct foo{
foo(A & self) {
self.data+=1;
std::cout << "A" << std::endl;
}
};
void printme() {
std::cout << data << std::endl;
}
};
struct B : virtual public A {
struct foo : virtual public A::foo {
foo(B & self) : A::foo(self) {
self.data+=2;
std::cout << "B" << std::endl;
}
};
};
struct C : virtual public A {
struct foo : virtual public A::foo {
foo(C & self) : A::foo(self) {
self.data+=4;
std::cout << "C" << std::endl;
}
};
};
struct D : public B, public C{
struct foo : public B::foo, public C::foo {
foo(D & self) : A::foo(self) , B::foo(self), C::foo(self) {
self.data+=8;
std::cout << "D" << std::endl;
}
};
};
int main() {
D d;
(D::foo(d));
d.printme();
}
Essentially, the call (D::foo(d)) creates a temporary who's constructor does the actions we desire. We pass in the object d by hand in order to access to the memory. Since the classes foo are inside of the classes A..D, this gives us access to the protected members.
Just an implementation of polkadotcadaver's idea. Here, Limiter is designed to be a reusable mechanism for this, and the virtual base class should have a member of that type. The controlled base-class function uses bool Limiter::do_next() to ask whether it should run "as usual" or return immediately, while the derived classes calling the base-class function get a scope-guard object from the limiter that takes ownership if not already claimed, and releases any ownership it had on destruction.
#include <iostream>
class Limiter
{
public:
Limiter() : state_(Unlimited) { }
class Scope
{
public:
Scope(Limiter& l)
: p_(l.state_ == Unlimited ? &l : NULL)
{ if (p_) p_->state_ = Do_Next; }
~Scope() { if (p_) p_->state_ = Unlimited; }
private:
Limiter* p_;
};
Scope get() { return Scope(*this); }
bool do_next()
{
if (state_ == Do_Next) { state_ = Suspended; return true; }
return state_ != Suspended;
}
private:
enum State { Unlimited, Do_Next, Suspended } state_;
};
struct A {
Limiter limiter_;
virtual void foo() {
if (limiter_.do_next())
std::cout << "A" << std::endl;
}
};
struct B : virtual public A {
virtual void foo() {
Limiter::Scope ls = A::limiter_.get();
A::foo();
std::cout << "B" << std::endl;
}
};
struct C : virtual public A {
virtual void foo() {
Limiter::Scope ls = A::limiter_.get();
A::foo();
std::cout << "C" << std::endl;
}
};
struct D : public B, public C{
virtual void foo() {
Limiter::Scope ls = A::limiter_.get();
B::foo();
C::foo();
std::cout << "D" << std::endl;
}
};
int main() {
D d;
d.foo();
}
Discussion of technique edited into your question
Took me a while to work out what you were doing in your code ;-P - so for the sake of discussion I'll post what I boiled it down to:
#include <iostream>
namespace foo {
struct A {
A() { std::cout << "A\n"; }
};
struct B : virtual public A {
B() { std::cout << "B\n"; }
};
struct C : virtual public A {
C() { std::cout << "C\n"; }
};
struct D : public B, public C{
D() { std::cout << "D\n"; }
};
}
struct A { virtual void foo() { foo::A(); } };
struct B : virtual public A { void foo() { foo::B(); } };
struct C : virtual public A { void foo() { foo::C(); } };
struct D : public B, public C { void foo() { foo::D(); } };
int main() {
D d;
d.foo();
}
For others' sake - this works by having the A..D::foo() functions create temporary objects of types foo::A..D, the constructors for which honour the virtual base designation so foo::A::A() is only called once.
As a general solution, an issue with this is that you have to manually synchronise the foo:: structures, so there's redundancy and fragility. It's clever though!