C++ passing unknown type to a virtual function
我用C++编写,我想把一个未知类型(只知道在运行时)传递给一个纯虚函数:
1 | virtual void DoSomething(??? data); |
其中,
我计划使用模板,但因为它实现了虚拟函数和模板不能一起工作:C++类成员函数模板可以是虚拟的吗?
我希望避免对传递给函数的所有类(类似于C中的对象)使用基类。
提前谢谢
你需要打字擦。这样的一个例子是通用EDCOX1〔0〕(和在C++ 17中EDCOX1〔1〕〕。
1 | virtual void DoSomething(boost::any const& data); |
然后,每个子类都可以尝试安全的
1 2 3 4 5 6 7 | void DoSomething(boost::any const& data) { auto p = any_cast<std::string>(&data); if(p) { // do something with the string pointer we extracted } } |
当然,如果您所寻求的行为范围受到更多限制,您可以推出自己的类型擦除抽象。
类型擦除不是唯一的可能性。
您可能对使用访问者模式感兴趣:将std::variant作为参数,并使用包含要实现的模板代码的lambda访问它:
1 2 3 4 | virtual void doSomething(std::variant<int,float/*,...*/> data) { visit([=](auto v){/*...*/;},data); } |
如果您不想使用Boosi/C++17,请考虑从基类派生"doMeMeTeNT"函数的参数,并将动态CAST转换为正确的类对象。在这种情况下,您可以在运行时签入一个有效指针。
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 | class param{ public: virtual ~param(){}; }; template <typename T> struct specificParam:param{ specificParam(T p):param(p){} T param; }; class Foo { public: virtual void doSomething(param* data) = 0; }; template <typename T> class Bar : public Foo { public: virtual void doSomething(param* data){ specificParam<T> *p = dynamic_cast<specificParam<T> *>(data); if (p != nullptr){ std::cout<<"Bar got:" << p->param <<" "; } else { std::cout<<"Bar: parameter type error. "; } } }; int main(){ Bar<char> obj1; Bar<int> obj2; Bar<float> obj3; specificParam<char> t1('a'); specificParam<int> t2(1); specificParam<float> t3(2.2); obj1.doSomething(&t1); //Bar got:a obj2.doSomething(&t2); //Bar got:1 obj3.doSomething(&t3); //Bar got:2.2 // trying to access int object with float parameter obj2.doSomething(&t3); //Bar: parameter type error. } |
最简单(但不安全!)方法是使用void*指针+静态强制转换
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 | class Foo { public: virtual void doSomething(void* data) = 0; }; template <typename T> class Bar:public Foo { public: virtual void doSomething(void* data){ T* pData = static_cast<T*>(data); std::cout<<"Bar1 got:" << *pData <<" "; } }; int main(){ Bar<char> obj1; Bar<int> obj2; Bar<float> obj3; char c = 'a'; int i = 1; float f = 2.2; obj1.doSomething(&c); // Bar1 got:a obj2.doSomething(&i); // Bar1 got:1 obj3.doSomething(&f); // Bar1 got:2.2 //obj2.doSomething(&c); // Very bad!!! } |
像那样?:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Foo { virtual ~Foo() = 0; }; template <typename T> class Bar : public Foo { T object; } ... virtual void DoSomething(Foo* data) { Bar<int>* temp = dynamic_cast<Bar<int>*>(data); if (temp) std::count<<temp->object; } |