C 将未知类型传递给虚拟函数

C++ passing unknown type to a virtual function

本文关键字:虚拟 函数 未知 类型      更新时间:2023-10-16

我正在用C 写作,我想将未知类型(仅在运行时间中知道)转到纯虚拟函数:

virtual void DoSomething(??? data);

其中 DoSomething是派生类中纯虚拟函数的实现。

我计划使用模板,但是当事实证明虚拟函数,模板不能一起使用:C 类成员功能模板可以虚拟吗?

我想避免使用我传递给该功能的所有类的基类(类似于C#中的对象)。

预先感谢

您需要类型擦除。一个例子是通用boost::any(C 17中的std::any)。

virtual void DoSomething(boost::any const& data);

,然后每个子级都可以尝试 SAFE any_cast以获取其期望的数据。

void DoSomething(boost::any const& data) {
  auto p = any_cast<std::string>(&data);
  if(p) {
    // do something with the string pointer we extracted
  }
}

,如果您寻求的行为范围更加限制,您当然可以推出自己的类型删除抽象。

如果您不想使用boost/c 17,请考虑从基类中派生'剂量米仪的参数,然后将动态铸造到正确的类对象。在这种情况下,您可以在运行时检查有效的指针。

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 << "n";
        }
        else {
            std::cout<<"Bar: parameter type error.n";
        }
    }
};
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* pointer static cast

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 << "n";
    }
};
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!!!     
}

type-erasure不是唯一的可能性。

您可能有兴趣使用访问者模式:以参数为std ::变体,并使用包含要实现的模板代码的lambda访问它:

virtual void doSomething(std::variant<int,float/*,...*/> data)
   {
   visit([=](auto v){/*...*/;},data);
   }

类似的东西?:

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