Date: Sat, 16 Apr 2022 14:22:41 +0100
On Saturday, April 16, 2022, Frederick Virchanza Gotham wrote:
>
> This sample experimental code has two problems:
>
> (1) It invokes the base method twice on the same object
> (2) It doesn't compile because of casting to a virtual base
>
> but I think you see the idea of what I'm trying to do.
>
The following is something along the lines of what my 'precompiler' will
produce. The following self-sufficient source file compiles successfully
and runs properly:
#include <iostream>
using std::cout;
using std::endl;
class Laser {
public:
virtual bool Trigger(void)
{
cout << "Laser" << endl;
return true;
}
};
class Laser_Nitrogen : virtual public Laser {
public:
bool Trigger(void) override
{
cout << "Laser_Nitrogen" << endl;
return false;
}
};
class Laser_PicoSecond : virtual public Laser {
public:
bool Trigger(void) override
{
cout << "Laser_PicoSecond" << endl;
return true;
}
};
class Laser_NitrogenPicoSecond : public Laser_Nitrogen, public
Laser_PicoSecond {
public:
bool Trigger(void) override;
};
class IMethodInvoker {
protected:
// All methods have one extra
// parameter for 'this' as 'void*'
virtual bool Trigger(void*) = 0;
friend class Invoker;
};
class Invoker final {
protected:
IMethodInvoker &_mi;
void *const _this;
public:
Invoker(IMethodInvoker &arg_mi, void *const arg_this) : _mi(arg_mi),
_this(arg_this) {}
// The extra 'this' parameter is no longer needed
bool Trigger(void) // not virtual
{
return _mi.Trigger(_this);
}
};
template<class Base, class Derived>
class MethodInvoker final : public IMethodInvoker {
protected:
void (*const _method)(void);
public:
MethodInvoker(void (*const arg_method)(void)) : _method(arg_method) {}
protected:
// All methods have one extra
// parameter for 'this' as 'void*'
bool Trigger(void *const arg_this) override
{
Base *const p = static_cast<Base*>(static_cast<Derived*>(arg_this));
// I'm using a union here
// because g++ gives a
// compiler error for
// reinterpret_cast
union {
void (*f)(void);
bool (Base::*m)(void);
} const fm = { _method };
return (p->*fm.m)();
}
};
bool Laser_NitrogenPicoSecond::Trigger(void)
{
static MethodInvoker<Laser,Laser_NitrogenPicoSecond> mi_Laser(
reinterpret_cast<void(*)(void)>(&Laser::Trigger) );
static MethodInvoker<Laser_Nitrogen,Laser_NitrogenPicoSecond>
mi_Laser_Nitrogen(
reinterpret_cast<void(*)(void)>(&Laser_Nitrogen::Trigger) );
static MethodInvoker<Laser_PicoSecond,Laser_NitrogenPicoSecond>
mi_Laser_PicoSecond(
reinterpret_cast<void(*)(void)>(&Laser_PicoSecond::Trigger) );
Invoker methods[] =
{
Invoker(mi_Laser, this),
Invoker(mi_Laser_Nitrogen, this),
Invoker(mi_Laser_PicoSecond, this),
};
for ( auto inv : methods )
{
inv.Trigger();
//if ( inv->Trigger() ) return true;
}
cout << "Laser_NitrogenPicoSecond" << endl;
return false;
}
int main(void)
{
cout << "=== First Line ===" << endl;
Laser_NitrogenPicoSecond obj;
obj.Trigger();
cout << "=== Last Line ===" << endl;
}
I just need to figure a strategy for how to avoid calling the same method
twice on the same Base object in cases of virtual inheritance.
>
> This sample experimental code has two problems:
>
> (1) It invokes the base method twice on the same object
> (2) It doesn't compile because of casting to a virtual base
>
> but I think you see the idea of what I'm trying to do.
>
The following is something along the lines of what my 'precompiler' will
produce. The following self-sufficient source file compiles successfully
and runs properly:
#include <iostream>
using std::cout;
using std::endl;
class Laser {
public:
virtual bool Trigger(void)
{
cout << "Laser" << endl;
return true;
}
};
class Laser_Nitrogen : virtual public Laser {
public:
bool Trigger(void) override
{
cout << "Laser_Nitrogen" << endl;
return false;
}
};
class Laser_PicoSecond : virtual public Laser {
public:
bool Trigger(void) override
{
cout << "Laser_PicoSecond" << endl;
return true;
}
};
class Laser_NitrogenPicoSecond : public Laser_Nitrogen, public
Laser_PicoSecond {
public:
bool Trigger(void) override;
};
class IMethodInvoker {
protected:
// All methods have one extra
// parameter for 'this' as 'void*'
virtual bool Trigger(void*) = 0;
friend class Invoker;
};
class Invoker final {
protected:
IMethodInvoker &_mi;
void *const _this;
public:
Invoker(IMethodInvoker &arg_mi, void *const arg_this) : _mi(arg_mi),
_this(arg_this) {}
// The extra 'this' parameter is no longer needed
bool Trigger(void) // not virtual
{
return _mi.Trigger(_this);
}
};
template<class Base, class Derived>
class MethodInvoker final : public IMethodInvoker {
protected:
void (*const _method)(void);
public:
MethodInvoker(void (*const arg_method)(void)) : _method(arg_method) {}
protected:
// All methods have one extra
// parameter for 'this' as 'void*'
bool Trigger(void *const arg_this) override
{
Base *const p = static_cast<Base*>(static_cast<Derived*>(arg_this));
// I'm using a union here
// because g++ gives a
// compiler error for
// reinterpret_cast
union {
void (*f)(void);
bool (Base::*m)(void);
} const fm = { _method };
return (p->*fm.m)();
}
};
bool Laser_NitrogenPicoSecond::Trigger(void)
{
static MethodInvoker<Laser,Laser_NitrogenPicoSecond> mi_Laser(
reinterpret_cast<void(*)(void)>(&Laser::Trigger) );
static MethodInvoker<Laser_Nitrogen,Laser_NitrogenPicoSecond>
mi_Laser_Nitrogen(
reinterpret_cast<void(*)(void)>(&Laser_Nitrogen::Trigger) );
static MethodInvoker<Laser_PicoSecond,Laser_NitrogenPicoSecond>
mi_Laser_PicoSecond(
reinterpret_cast<void(*)(void)>(&Laser_PicoSecond::Trigger) );
Invoker methods[] =
{
Invoker(mi_Laser, this),
Invoker(mi_Laser_Nitrogen, this),
Invoker(mi_Laser_PicoSecond, this),
};
for ( auto inv : methods )
{
inv.Trigger();
//if ( inv->Trigger() ) return true;
}
cout << "Laser_NitrogenPicoSecond" << endl;
return false;
}
int main(void)
{
cout << "=== First Line ===" << endl;
Laser_NitrogenPicoSecond obj;
obj.Trigger();
cout << "=== Last Line ===" << endl;
}
I just need to figure a strategy for how to avoid calling the same method
twice on the same Base object in cases of virtual inheritance.
Received on 2022-04-16 13:22:43