Virtual visitor - c++

I have a hierarchy of classes (Base and daugthers A, B, C and so on). The hierarchy tree is not finite. It’s possible to visit a Base* using the well-known visitor pattern in order to dynamically adapt to the dynamic type of Base*. The visitor has a type, like BaseVisitor. Like this:
struct BaseVisitor;
struct Base {
virtual void accept(BaseVisitor &v) = 0;
};
struct A : Base {
int a;
A(int x) : a(x) {}
~A(void) = default;
void accept(BaseVisitor &v) override {
v->visit(*this);
}
};
struct B : Base {
float b;
B(void) : b(314.f) {}
~B(void) = default;
void accept(BaseVisitor &v) override {
v->visit(*this);
}
};
struct BaseVisitor {
void visit(Base &) {}
void visit(A &a) {
std::cout << "just visited a A; a=" << a.a << std::endl;
}
void visit(B &b) {
std::cout << "just visited a B; b=" << b.b << std::endl;
}
};
Now, I’d like to make BaseVisitor an abstract class in order to inherits new visitors. The issue comes when I want to define the abstract class:
struct ABaseVisitor {
virtual void visit(Base &) = 0; /* huh? */
};
Do you have any idea?

Related

Runtime polymorphism for two different classes

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");
}

Multiple "level" derived abstract classes with

I have a problem in C++ where I have
One abstract base class with common members and pure virtual functions. This is A in the code below.
Multiple derived classes with different members and functions. This is B and C in the code below.
Multiple derived classes that implements the virtual functions and has no new members. This is do_stuff_1 and do_stuff_2 in the code below.
My solution so far is to mix templates and abstract classes. The goal is to hold a pointer to the abstract classes B orC and call do_stuff. My questions are
Is my solution a good one?
If not, are there better solutions?
If so, are there some pitfalls I should be aware of?
Here is my solution so far
#include <iostream>
#include <memory>
/* base virtual class */
class A {
public:
int a;
A(int a) : a(a) {}
virtual void do_stuff() = 0;
};
/* concrete implementations of do_stuf */
template<class T>
class do_stuff_1 : public T {
public:
using T::T;
void do_stuff(){
std::cout << "do_stuff_1 " << this->a << std::endl;
}
};
template<class T>
class do_stuff_2 : public T {
public:
using T::T;
void do_stuff(){
std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
}
};
/* derived classes from A */
class B : public A {
public:
int b; // one member here but many more in my application
B(int a, int b): A(a), b(b) {}
};
class C : public A {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): A(a), c(c) {}
};
int main() {
std::unique_ptr<B> x;
x.reset(new do_stuff_1<B>(1, 1));
x->do_stuff();
std::cout << x->b << std::endl;
x.reset(new do_stuff_2<B>(1, 2));
x->do_stuff();
std::cout << x->b << std::endl;
std::unique_ptr<C> z;
z.reset(new do_stuff_1<C>(1, "Yo"));
z->do_stuff();
std::cout << z->c << std::endl;
z.reset(new do_stuff_2<C>(1, "Hello"));
z->do_stuff();
std::cout << z->c << std::endl;
return 0;
}
The result is
do_stuff_1 1
1
do_stuff_2 2
2
do_stuff_1 1
Yo
do_stuff_2 2
Hello
Your solution seems fine. It's a compile time approach and you create 4 different objects.
The main drawbacks are:
you won't know if the do_stuff() code is correct unless you instantiate the template.
you could instantiate do_stuff_1 or do_stuff_2 with classes which are not of base class A. You should at least use override in the template to make sure it overrides a virtual function.
Here a small improvement to address these issues:
template<class T>
class do_stuff_2 : public T {
public:
using T::T;
void do_stuff() override {
static_assert (std::is_base_of<A, T>::value, "T should be derived from A");
std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
}
};
By the way, using make_unique would be nice.
To me looks like some kind of policy, this may look like:
#include <iostream>
#include <memory>
#include <type_traits>
struct AwayToDoTheStuff {
virtual void operator()(int a) = 0;
virtual ~AwayToDoTheStuff() {}
};
/* concrete implementations of do_stuf */
class HowToDoStuff1 : public AwayToDoTheStuff {
public:
void operator()(int a) override {
std::cout << "do_stuff_1 " << a << std::endl;
}
};
class HowToDoStuff2 : public AwayToDoTheStuff {
public:
void operator()(int a) override {
std::cout << "do_stuff_2 " << a + 1 << std::endl;
}
};
/* base virtual class */
template <class HowToDoStuff>
class A {
public:
int a;
A(int a) : a(a) {}
void do_stuff() {
static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
HowToDoStuff()(a);
}
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public A<HowToDoStuff> {
public:
int b; // one member here but many more in my application
B(int a, int b): A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public A<HowToDoStuff> {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): A<HowToDoStuff>(a), c(c) {}
};
int main() {
B<HowToDoStuff1>(1, 1).do_stuff();
B<HowToDoStuff2>(1, 2).do_stuff();
C<HowToDoStuff1>(1, "Yo").do_stuff();
C<HowToDoStuff2>(1, "Hello").do_stuff();
return 0;
}
but I must say this is quite hard to tell if a solution match well with an example that much generic. I hope it will help you in some ways...
EDIT:
You seem to need to have a common base class so that you can pass your objects B and C to a common function of the kind void f(A &a);
Then my example can be adapted that way:
/* base virtual class */
class A {
public:
void do_stuff() = 0;
};
template <class HowToDoStuff>
class Policy_A : public A {
public:
int a;
A(int a) : a(a) {}
void do_stuff() override {
static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
HowToDoStuff()(a);
}
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public Policy_A<HowToDoStuff> {
public:
int b; // one member here but many more in my application
B(int a, int b): Policy_A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public Policy_A<HowToDoStuff> {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): Policy_A<HowToDoStuff>(a), c(c) {}
};
So that the do_stuff can be called on opaque A objects.
You may also pass the HowToDoStuff object at creation:
/* base virtual class */
class A {
std::unique_ptr<AwayToDoTheStuff> _stuffer;
public:
int a;
A(std::unique_ptr<AwayToDoTheStuff> stuffer, int a) : _stuffer(std::move(stuffer)), a(a) {}
void do_stuff() {
(*_stuffer)(a);
}
};
/* derived classes from A */
class B : public A {
public:
int b; // one member here but many more in my application
B(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, int b): A(std::move(stuffer), a), b(b) {}
};
class C : public A {
public:
std::string c; // one member here but many more in my application
C(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, std::string c): A(std::move(stuffer), a), c(c) {}
};
int main() {
auto stuffer1forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
auto stuffer2forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
B(stuffer1forB, 1, 1).do_stuff();
B(stuffer2forB, 1, 2).do_stuff();
auto stuffer1forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
auto stuffer2forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
C(stuffer1forC, 1, "Yo").do_stuff();
C(stuffer2forC, 1, "Hello").do_stuff();
return 0;
}

Virtual template function in c++

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.

Automatic method selection based on class instance

I have two variants of the same method. I also have an instance of a base class type, but I don't know what specific class it is an instance of. I now want to automatically select the appropriate method depending on the actual type of the object. It seems impossible though and the only solution I can come up with is to check all possibilities by casting.
There has to be a nicer solution though.
Here is my minimal example:
// Example program
#include <iostream>
#include <string>
#include <memory>
class A
{
public:
virtual void bar() const = 0;
};
class B : public A
{
public:
void bar() const
{
std::cout << "B.bar()" << std::endl;
}
};
class C : public A
{
public:
void bar() const
{
std::cout << "C.bar()" << std::endl;
}
};
class Z
{
public:
Z(int variable) : m_variable(variable) {};
void foo(std::shared_ptr<B> b)
{
std::cout << "Calling foo(B) method! " << m_variable << std::endl;
b->bar();
}
void foo(std::shared_ptr<C> c)
{
std::cout << "Calling foo(C) method!" << m_variable << std::endl;
c->bar();
}
private:
int m_variable;
};
int main()
{
std::shared_ptr<A> b(new B());
Z z(42);
//z.foo(b); // This doesn't work
// But this does
std::shared_ptr<B> b_cast = std::dynamic_pointer_cast<B>(b);
if (b_cast.get())
z.foo(b_cast);
}
http://cpp.sh/9fqne
At the moment I have to resort to dynamic_pointer_cast, but I find it kinda ugly and not very maintainable.
I also don't want to add the functionality of foo() to the classes B and C, because those are small independent data structures on which many other classes operate.
Thank you very much!
EDIT: In the original post I simplified a bit too much. The new example should clear things up.
Add a pure virtual function foo() to your base class and override in subsequent derived classes. Then have your global function foo() (which has nothing to do with member functions with the same name) accept a reference to std::shared_ptr const as a parameter:
#include <iostream>
#include <memory>
class A{
public:
virtual void foo() = 0;
};
class B : public A{
public:
void foo() override{
std::cout << "Calling foo(B) method!" << std::endl;
}
};
class C : public A{
public:
void foo() override{
std::cout << "Calling foo(C) method!" << std::endl;
}
};
void foo(const std::shared_ptr<A>& param){
param->foo();
}
int main(){
std::shared_ptr<A> b = std::make_shared<B>();
std::shared_ptr<A> c = std::make_shared<C>();
foo(b);
foo(c);
}
As BoBTFish pointed out, the visitor pattern is a potential solution for this problem:
// Example program
#include <iostream>
#include <string>
#include <memory>
class B;
class C;
class Visitor
{
public:
virtual void visit(B* b) const = 0;
virtual void visit(C* b) const = 0;
};
class A
{
public:
virtual void bar() const = 0;
virtual void accept(const Visitor* visitor) = 0;
};
class B : public A
{
public:
void bar() const
{
std::cout << "B.bar()" << std::endl;
}
void accept(const Visitor* visitor)
{
visitor->visit(this);
}
};
class C : public A
{
public:
void bar() const
{
std::cout << "C.bar()" << std::endl;
}
void accept(const Visitor* visitor)
{
visitor->visit(this);
}
};
class Z : public Visitor
{
public:
Z(int variable) : m_variable(variable) {};
void visit(B* b) const
{
std::cout << "Calling foo(B) method! " << m_variable << std::endl;
b->bar();
}
void visit(C* c) const
{
std::cout << "Calling foo(C) method!" << m_variable << std::endl;
c->bar();
}
private:
int m_variable;
};
int main()
{
std::shared_ptr<A> b(new B());
Z z(42);
b->accept(&z);
}
http://cpp.sh/2vah5
Thank you very much!

C++ virtual functions base return type suggestions

I need a base class that gives me primitive type of data's pointer. I add a function in it. I derived types of class. I used void * to support all primitive types as a return type but it is like old C days. It is not good for OOP. Does one have an suggestion to do in a proper way in OOP?
#include <iostream>
class base {
public:
virtual void *getPtr() = 0;
virtual ~base() {};
};
class derivedAType : public base {
protected:
int _i;
public:
derivedAType(int i): _i(0) { _i = i; };
virtual ~derivedAType() {}
virtual void *getPtr() {
return static_cast<void *>(&_i);
}
};
class derivedBType : public base {
protected:
short _s;
public:
derivedBType(short s): _s(0) { _s = s; };
virtual ~derivedBType() {}
virtual void *getPtr() {
return static_cast<void *>(&_s);
}
};
int main()
{
base *b1 = new derivedAType(1203912);
base *b2 = new derivedBType(25273);
std::cout << "b1 : " << *(static_cast<int *>(b1->getPtr()))
<< "\nb2 : " << *(static_cast<short *>(b2->getPtr()))
<< std::endl;
delete b2;
delete b1;
return 0;
}
Make the base class a template class with the data type as the template variable
template<typename DataType>
class base {
virtual DataType* getPtr() = 0;
//...
};
and
class derivedAType : public base<int>
But this changes base class to a template class which means you cant store them together, base<int> is different from base<short>
If this isnt acceptable, the other options is just a tad bit cleaner than your code but abt the same, refer to this question. Basically derived class return types can reflect their true type and i think it should get automatically converted to void*, so you dont have to manually cast the pointer.
Not sure about your problem. But maybe a double callback can help:
class Callback {
public:
virtual void do_int( int i ) const = 0;
virtual void do_short( short s ) const = 0;
/* ... */
}
class base {
public:
virtual void do_stuff(const Callback & c); /* will need a more telling name */
virtual ~base() {};
};
class derivedAType : public base {
protected:
int _i;
public:
derivedAType(int i): _i(0) { _i = i; };
virtual ~derivedAType() {}
virtual void do_stuff(const Callback & c) {
c.do_int( _i );
}
};
class derivedBType : public base {
protected:
short _s;
public:
derivedBType(short s): _s(0) { _s = s; };
virtual ~derivedBType() {}
virtual void do_stuff( const Callback & c) {
c.do_short( _s );
}
};
class print_callback : public Callback {
public:
virtual void do_int( int i ) const { std::cout << i; }
virtual void do_short( short s ) const { std::cout << s; }
}
int main() {
base *b1 = new derivedAType(1203912);
base *b2 = new derivedBType(25273);
std::cout << "b1 : ";
b1->do_stuff(print_callback());
std::cout << "\nb2 : ";
b2->do_stuff(print_callback());
std::cout << std::endl;
delete b2;
delete b1;
return 0;
}
Of course you can simplify this by just storing the created print callback, and using it twice.