关于模板:C++将未知类型传递给虚函数

C++ passing unknown type to a virtual function

我用C++编写,我想把一个未知类型(只知道在运行时)传递给一个纯虚函数:

1
virtual void DoSomething(??? data);

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

我计划使用模板,但因为它实现了虚拟函数和模板不能一起工作:C++类成员函数模板可以是虚拟的吗?

我希望避免对传递给函数的所有类(类似于C中的对象)使用基类。

提前谢谢


你需要打字擦。这样的一个例子是通用EDCOX1〔0〕(和在C++ 17中EDCOX1〔1〕〕。

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

然后,每个子类都可以尝试安全的any_cast以获得它期望的数据。

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