c++ - Automatic downcast of a pointer to a derived object -
good morning,
i have templatized class , want manipulate objects vector of pointers. use vector of pointers templatized class need class derived non-templatized class, , did it.
here's problem: call method of derived class pointer base class, cannot use virtual functions because template functions can't made virtual. need make explicit cast, tedious: once create number object new, in fact, downcast need made number*, although object known number in advance.
i solved problem in awkward way: function myset tests supported values of typeid correct dynamic cast. long series of nested ifs perform typeid checking.
besides tediousness, function works calling 'set' method, , similar functions should defined calling other methods. if make automatic casting kind of object i'm pointing to, simpler.
the cons of approach are:
- the code repetitive: if defined function (such t get() {return val;}, need myget function full set of nested ifs!
- the list of supported types must explicitly defined nesting if calls
- the code may inefficient
the compiler knows lst[0] (in code below) points number object, although lst vector of element objects number<> objects derived.
is there method automatically downcast pointer defined base* pointer object pointed at?
if had correct downcasting, define thousands of methods in number<> class , call them propercasting -> function(...) call
here's code (it works properly, core definition of "myset")
thanks in advance, pietro m.
ps i'm interested in standard c++ approach without using other libraries except stl, such boost.
#include <iostream> #include <vector> #include <typeinfo> using namespace std; class element { public: virtual void print() = 0; // print not templatized , works //template <class t> virtual set(t v) = 0; // solve problems, if legal. }; template <class t> class number : public element { t val; public: void print() {cout << "number " << val << endl;} void set(t v) {val = v;} }; // that's best can do! template <class t> void myset(t v, element *ptr) { // there kink in template: compiler checks t type value of v, in case integer: // cout << "type name template is: " << typeid(t).name() << endl; // cout << "type name integer is: " << typeid(int).name() << endl; if (typeid(*ptr) == typeid(number<double>)) { ((number<double> *) ptr) -> set(7); return; } else if (typeid(*ptr) == typeid(number<float>)) { ((number<float> *) ptr) -> set(7); return; } // add other types... (tedious) else { cout << "type not supported" << endl; } } int main() { vector <element *> lst; // list of heterogeneous templatized objects lst.push_back(new number<float>); lst.push_back(new number<double>); lst[0] -> print(); //((number<float> *) lst[0]) -> set(7); it's correct requires know type when call (tedious) myset(7, lst[0]); // may inefficient, works (for types explicitly supported) // cast_to_what_the_pointer_actually_points_to <lst[0]> -> set(7); // that's i'd do: downcast function checks object type , returns correct pointer able call class method... lst[0] -> print(); }
you're there. need have templated set
method calls private virtual method typeid
, void *
pointer argument, allowing override decide how handle it:
class element { virtual void set_impl(const std::type_info &, const void *) = 0; public: template <class t> void set(t v) { set_impl(typeid(v), &v); } };
and example of how write set_impl
:
template <class t> class number : public element { t val; void set_impl(const std::type_info &ti, const void *pv) { if (ti == typeid(t)) { val = *static_cast<const t *>(pv); } else { throw std::invalid_argument("incorrect type set()"); } } };
this similar approach taken boost.any.
Comments
Post a Comment