Tipo astratto generico C ++
-
13-11-2019 - |
Domanda
Voglio definire una classe generica in C ++ che consente di eseguire il mio algoritmo su qualsiasi dati. Il problema è che questi dati possono essere qualsiasi cosa (ad esempio un vettore di galleggianti, un grafico, ecc.). È possibile dire nella mia classe che i dati manipolati sono di tipo T che può essere qualcosa? Quindi l'utente della mia classe dovrà implementare alcuni metodi della mia classe rispetto alla manipolazione dei suoi dati (ad esempio, a seconda dei suoi dati, definisce come fare una somma di due dati, ecc ...)
Modificare:
Come è possibile quindi istanziare il modello di classe e chiamare il suo metodo? Ho un errore quando lo faccio:
MyClass<int, int> tst();
tst.test(3, 4); // or even with tst.test<int, int>(3, 4);
Errore: richiesta per il membro "test" in "TST", che è di tipo non di classe 'myclass ()'
La classe se definita come:
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
using namespace std;
using namespace boost;
template<typename T1, typename T2>
class MyClass
{
public:
MyClass();
virtual ~MyClass();
void test(T1 p, T2 s);
protected:
struct NodeData
{
T1 var1;
T2 var2;
int var3;
};
struct EdgeData
{
int var;
};
typedef adjacency_list<setS, setS, undirectedS, NodeData, EdgeData> Graph;
typedef typename Graph::vertex_descriptor NodeDataID;
typedef typename Graph::edge_descriptor EdgeDataID;
typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;
Graph g;
};
template<typename T1, typename T2>
void MyClass<T1, T2>::test(T1 arg1, T2 arg2)
{
NodeDataID nId = add_vertex(g);
g[nId].anything = "but anything is not in struct NodeData !";
g[nId].var1 = arg1;
g[nId].var2 = arg2;
g[nId].var3 = 55;
}
template<typename T1, typename T2>
MyClass<T1, T2>::MyClass()
{
// ...
}
template<typename T1, typename T2>
MyClass<T1, T2>::~MyClass()
{
// ...
}
Soluzione
Come commenta @als, stai descrivendo perfettamente un modello di classe.
Puoi ottenere una buona gamba sull'argomento a http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2fcom.ibm.xlcpp8l.doc%2fLanguage%2fref%2fclass_templates.htm
Altri suggerimenti
Sì, puoi farlo, purché tutti i diversi tipi di dati che desideri utilizzare nella tua classe supportano le operazioni richieste dall'algoritmo.
Se si utilizzano metodi modello per le operazioni specifiche del tipo, i tuoi utenti possono specializzarli per le loro classi di input che richiedono qualcosa di diverso dall'implementazione predefinita.
Sull'ipotesi <T>
deve rimanere coerente:
Consiglierei di avere una lezione che assume un "gestore operativo". Il gestore delle operazioni trasmesso gestirà tutte le operazioni specifiche del tipo. Questo è un esempio incredibilmente approssimativo, e non sono nemmeno sicuro di quanto sia funzionale in quanto non lo implesso da un po 'di tempo e sto scrivendo C ++ senza il compilatore puramente dalla memoria. Detto questo, questo dovrebbe mostrare l'idea di base.
class CGenericOperationHandler<T>{
public:
Sum(<T> left,<T> right);
Subtract(<T> left,<T> right);
Multiply(<T> left,<T> right);
}
class CFloatOperationHandler : CGenericOperationHandler<float>{
public:
Sum(float left,float right){ return left + right; }
Subtract(float left,float right){ return left - right; }
Multiply(float left,float right){ return left * right; }
}
class CAlgoRunner<T>{
CGenericOperationHandler<T>* myOpHandler;
CAlgoRunner(CGenericOperationHandler<T>* opHandler){
myOpHandler = opHandler;
}
public:
<T> RunAlgo(<T> left, <T> right){
return myOpHandler.Multiply(left, right);
}
}
main(){
CFloatOperationHandler theOpHandler;
CAlgoRunner<float>* myRunner = new CAlgoRunner<float>( theOpHandler );
float result = myRunner.RunAlgo( 6.0f, 1.5f); //result is (6 * 1.5) i.e. 9
}
Funziona solo se si scrive in un file (.cpp per esempio). Se stai lavorando a grandi progetti con più file (intestazione e fonte) devi evitare i modelli perché il compilatore può vedere e analizzare i modelli quando vengono utilizzati. È un grosso problema perché la ridefinizione del modello è spesso un errore.