I would like to create some kind of factory function, but instead of returning a pointer to a certain class object, I would like to pass a pointer to the base class to a function as an argument. What makes it even more cumbersome, the function accepts the void pointer.
Here is the code I have tried.
#include <iostream>
#include <string>
class Base {
public:
std::string isA()
{
return "Base";
}
};
class Derived : public Base {
public:
std::string isA()
{
return "Derived";
}
};
void func(void* obj)
{
Derived* derived_ptr = (Derived*)obj;
std::cout << "Address of derived_ptr " << derived_ptr << "\n";
std::cout << "From func " << derived_ptr->isA() << "\n";
}
int main()
{
Base* instance;
func(instance);
std::cout << "Address of instance " << instance << "\n";
std::cout << "From main " << instance->isA() << "\n";
}
Output:
Address of derived_ptr 0x4009b0
From func Derived
Address of instance 0x4009b0
From main Base
From the output it is obvious that the addresses are the same but in each case it is different object (Base and Derived. Is there a way to get it working in this form?
If you do not want run time polymorphism via virtual
functions, you can use std::variant
instead. This enables you to use unrelated objects without a common base class, it did not need to enable RTTI which means it will fit also for small embedded systems and it still type safe as std::variant
keeps the information which object is currently stored inside the variant variable.
You also can store such variants in containers as you like. If you use a std::variant
with a pointer type, the potential waste by using this kind of union is only the additional pointer instance.
But yes, it has another indirection by using the pointer, but in your example you also have a void*
and "some mind" of check and conversion like a cast.
class Base {
public:
std::string isA()
{
return "Base";
}
};
class Derived : public Base {
public:
std::string isA()
{
return "Derived";
}
};
class Another
{
public:
std::string isA() { return "Another"; }
};
using VAR_T = std::variant< std::unique_ptr<Base>, std::unique_ptr<Derived>, std::unique_ptr<Another> >;
VAR_T Factory( int what )
{
switch ( what )
{
case 0: return VAR_T{std::make_unique<Base>()};
case 1: return VAR_T{std::make_unique<Derived>()};
case 2: return VAR_T{std::make_unique<Another>()};
}
return {};
}
/* Never do such thing in real world code!!!!!!!!!!!!!!!!! */
void func(void* obj)
{
VAR_T* var = reinterpret_cast< VAR_T* >( obj );
std::string s = std::visit( []( auto& ptr ){ return ptr->isA(); }, *var);
std::cout << "From func " << s << "\n";
}
int main()
{
std::vector< VAR_T > vars;
for ( int i = 0; i<3; i++)
{
vars.push_back( Factory( i ));
}
for ( auto& var: vars )
{
std::visit( []( auto& ptr ){ std::cout << ptr->isA() << std::endl; }, var );
}
// and now via void*, but never use this in production code. DANGEROUS, NOT TYPE SAFE,
for ( auto& var: vars )
{
func( &var );
}
}
EDIT: Added code with using void*
, BUT THIS SHOULD REALLY NEVER BE PART OF ANY PRODUCTION SYSTEM! void*
is always a nightmare!