sirve - C++ pasando un tipo desconocido a una función virtual
polimorfismo puro c++ (4)
¿algo como eso?:
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;
}
Estoy escribiendo en C ++ y quiero pasar un tipo desconocido (conocido solo en tiempo de ejecución) a una función virtual pura:
virtual void DoSomething(??? data);
donde DoSomething
es una implementación de una función virtual pura en una clase derivada.
Planeé usar plantillas pero, como resultado, la función virtual y las plantillas no funcionan juntas: ¿puede una plantilla de función miembro de la clase C ++ ser virtual?
Quiero evitar el uso de una clase base para todas las clases que pase a la función (algo así como el object en C #).
Gracias por adelantado
La eliminación de tipos no es la única posibilidad.
Tal vez le interese utilizar el patrón de visitante: tome como argumento una variante std :: y visítela con un lambda que contenga el código de plantilla que desea implementar:
virtual void doSomething(std::variant<int,float/*,...*/> data)
{
visit([=](auto v){/*...*/;},data);
}
Necesita borrado de tipo . Un ejemplo de esto es el boost::any
propósito general boost::any
(y std::any
en C ++ 17).
virtual void DoSomething(boost::any const& data);
Y luego, cada subclase puede intentar la any_cast
segura de any_cast
para obtener los datos que espera.
void DoSomething(boost::any const& data) {
auto p = any_cast<std::string>(&data);
if(p) {
// do something with the string pointer we extracted
}
}
Por supuesto, puede implementar su propio tipo borrando la abstracción si el rango de comportamientos que busca es más limitado.
Si no desea utilizar boost / C ++ 17, considere derivar el parámetro de la función ''doSometing'' de una clase base y realice la conversión dinámica al objeto de clase correcto. En este caso, puede verificar en tiempo de ejecución que tiene un puntero válido.
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.
}
La forma más simple (¡pero insegura!) Sería usar void * puntero + transmisión estática
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!!!
}