Automatic downcast of a pointer to a derived object
早上好,
我有一个模板化的类,我想通过指针向量来操作对象。要使用指向模板化类的指针向量,我需要从非模板化类派生这个类,我做到了。
我的问题是:要从指向基类的指针调用派生类的方法,我不能使用虚函数,因为模板函数不能变为虚函数。我需要做一个显式的强制转换,这很繁琐:一旦一个用新的创建了一个数字对象,实际上,需要对数字*进行强制转换,尽管已知该对象是提前编号的。
我用一种尴尬的方式解决了这个问题:函数myset测试typeid的所有支持值,以获得正确的动态强制转换。它是一系列嵌套的ifs,用于执行类型ID检查。
除了繁琐之外,函数只能用于调用"set"方法,并且应该为调用其他方法定义类似的函数。如果我能对我指向的对象进行自动投射,那就简单多了。
这种方法的缺点是:
编译器知道lst[0](在下面的代码中)指向一个数字对象,尽管lst是从中派生数字对象的元素对象的向量。
有没有一种方法可以自动将定义为base*的指针向下强制转换为指向实际指向的对象的指针?
如果我有正确的向下转换,那么我可以在number<>类中定义数千个方法,并使用propercasting->function(…)调用它们。
这是代码(它工作正常,核心是"myset"的定义)
事先谢谢,彼得洛M
PS我最感兴趣的是一个标准的C++方法,而不使用其他库,除了STL,如Boost。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #include <iostream> #include <vector> #include <typeinfo> using namespace std; class element { public: virtual void print() = 0; // print is not templatized and works properly //template <class T> virtual set(T v) = 0; // this would solve all my problems, if only it were legal. }; template <class T> class number : public element { T val; public: void print() {cout <<"number is" << val << endl;} void set(T v) {val = v;} }; // That's the best I can do! template <class T> void myset(T v, element *ptr) { // There is a kink in the template: the compiler checks the T type by the value of v, that in this case is an integer: // cout <<"Type name for the template is:" << typeid(T).name() << endl; // cout <<"Type name for an 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 but it requires I know the type when I call it (tedious) myset(7, lst[0]); // may be inefficient, but it works (for the types which are explicitly supported) // cast_to_what_the_pointer_actually_points_to <lst[0]> -> set(7); // that's what I'd like to do: a downcast function which checks the object type and returns the correct pointer would be able to call any class method... lst[0] -> print(); } |
你就快到了。您需要有一个模板化的
1 2 3 4 5 6 | 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); } }; |
以及如何编写
1 2 3 4 5 6 7 8 9 10 11 12 | 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 to set()"); } } }; |
这类似于boost.any所采用的方法。