Si consideri il seguente frammento di codice:Come posso evitare una chiamata virtuale quando conosco il tipo?
struct Base { virtual void func() { } };
struct Derived1 : Base { void func() override { print("1"); } };
struct Derived2 : Base { void func() override { print("2"); } };
class Manager {
std::vector<std::unique_ptr<Base>> items;
public:
template<class T> void add() { items.emplace_back(new T); }
void funcAll() { for(auto& i : items) i->func(); }
};
int main() {
Manager m;
m.add<Derived1>();
m.add<Derived2>();
m.funcAll(); // prints "1" and "2"
};
sto usando virtual
spedizione al fine di chiamare il override
metodo corretto da un std::vector
di oggetti polimorfici.
Tuttavia, so di che tipo sono gli oggetti polimorfici, poiché lo specifica in Manager::add<T>
.
La mia idea era di evitare una chiamata virtual
prendendo l'indirizzo della funzione membro T::func()
e memorizzandolo direttamente da qualche parte. Tuttavia, è impossibile, dal momento che avrei bisogno di memorizzarlo come void*
e di ricollocarlo nel Manager::funcAll()
, ma in quel momento non ho informazioni sul tipo.
La mia domanda è: sembra che in questa situazione ho più informazioni rispetto al solito per il polimorfismo (l'utente specifica il tipo derivato T
in Manager::add<T>
) - c'è un modo posso usare questo tipo di informazioni per evitare che un apparentemente inutili virtual
chiamata? (Un utente dovrebbe essere in grado di creare le proprie classi che derivano dalla Base
nel suo codice, tuttavia.)
"c'è un modo in cui posso utilizzare questo tipo di informazioni per evitare una chiamata virtuale apparentemente non necessaria?" Non cancellare quelle informazioni? ('unique_ptr ' digita la cancellazione qui). In ogni caso, "prendere l'indirizzo della funzione membro' T :: func() 'e memorizzarlo direttamente da qualche parte" è praticamente lo stesso della chiamata virtuale, tranne che con molto più lavoro da parte tua. –
@ R.MartinhoFernandes: capisco. Non vedo, tuttavia, un altro modo per memorizzare tipi che derivano da 'T', anche dopo aver specificato il tipo in' Manager :: add '- ricorda che l'utente deve definire i propri tipi che derivano da' Base' quindi non so quali saranno questi tipi. –
Quindi quello che vuoi è semplicemente impossibile da ottenere nel linguaggio (tuttavia, un compilatore potrebbe fare una tale ottimizzazione in questo codice di esempio, ma dubito che tu possa trovarlo nella pratica). È una classica situazione "non puoi mangiare la tua torta e la vuoi troppo": o cancelli i tipi, o ne mantieni i tipi. –