2012-03-07 13 views
12

Ho appena saputo cosa è veramente la std :: function e per cosa è usata e ho una domanda: ora che abbiamo essenzialmente delegati, dove e quando dovremmo usare Abstract Base Classes e quando, invece, dovrebbe implementare il polimorfismo tramite gli oggetti std :: function inseriti in una classe generica? ABC ha avuto un colpo fatale in C++ 11?Devo smettere di usare classi/interfacce di base astratte e usare invece boost :: function/std :: function?

Personalmente la mia esperienza fino ad ora è che il passaggio di delegati è molto più semplice da programmare rispetto alla creazione di più classi ereditate ognuna per un comportamento particolare ... quindi sono un po 'confuso quanto utile saranno le basi astratte d'ora in poi.

+2

In che modo 'std :: function' è diverso dai puntatori di funzione (* in questo contesto * quale)? Non vedo alcuna differenza. Se è così, allora cosa deve fare con C++ 11? È possibile utilizzare i puntatori di funzione per implementare il polimorfismo di runtime anche in pre-C++ 11. – Nawaz

+0

Non sono nemmeno sicuro di come iniziare a rispondere ... ad esempio std :: function può contenere un puntatore a funzioni con diverso tipo e numero di argomenti perché puoi std :: legarli prima di passare effettivamente ad esso. E, ovviamente, è molto più semplice da usare. Se potessi chiedere qualcosa su cosa può fare ciò che i _functors_ non possono ... questa domanda vorrei capire. Tuttavia, l'aggiunta del modo standard e * semplice * per creare delegati è ciò che ha generato comunque la mia domanda. – Zeks

+0

"* Tuttavia, l'aggiunta del modo standard e SEMPLICE per creare delegati è ciò che ha generato comunque la mia domanda. *" ... Ma non è * più semplice * dell'utilizzo di funzioni astratte di base e virtuali, allora qual è il punto? – Nawaz

risposta

19

Preferisco ben interfacce definite nel corso callback

Il problema con std::function (precedentemente boost::function) è che la maggior parte del tempo è necessario disporre di un callback a un metodo di classe, e quindi hanno bisogno di legarsi this per l'oggetto funzione. Tuttavia nel codice chiamante, non hai modo di sapere se this è ancora in circolazione. In effetti, non si ha idea che ci sia anche un this perché bind ha modellato la firma della funzione chiamante in ciò che richiede il chiamante.

Ciò può causare naturalmente arresti anomali quando il callback tenta di attivare metodi per classi che non esistono più.

È possibile, naturalmente, utilizzare shared_from_this e associare un shared_ptr a un callback, ma l'istanza potrebbe non andare mai via. La persona che ha una richiamata ora partecipa alla tua proprietà senza che nemmeno loro ne siano a conoscenza. Probabilmente vuoi una proprietà e una distruzione più prevedibili.

Un altro problema, anche se è possibile ottenere il callback per funzionare correttamente, è con callback, il codice può essere troppo disaccoppiato. Le relazioni tra gli oggetti possono essere così difficili da accertare che la leggibilità del codice diminuisca. Le interfacce, tuttavia, forniscono un buon compromesso tra un livello appropriato di disaccoppiamento con un rapporto chiaramente specificato come definito dal contratto dell'interfaccia. Puoi anche specificare più chiaramente, in questa relazione, problemi come chi possiede chi, ordine di distruzione, ecc.

Un ulteriore problema con std::function è che molti debugger non li supportano bene. In VS2008 e potenzia le funzioni, devi passare circa 7 livelli per arrivare alla tua funzione. Anche se tutte le altre cose sono uguali, una callback è stata la scelta migliore, la semplice seccatura e il tempo sprecato accidentalmente a scavalcare l'obiettivo di std::function è una ragione sufficiente per evitarlo. L'ereditarietà è una caratteristica fondamentale del linguaggio e il passaggio a un metodo sovrascritto di un'interfaccia è istantaneo.

Infine aggiungerò solo non abbiamo delegati in C++. I delegati in C# sono una parte fondamentale del linguaggio, proprio come l'ereditarietà è in C++ e C#. Abbiamo una funzionalità di libreria std che IMO è un livello rimosso da una funzionalità di base del linguaggio. Quindi non sarà così strettamente integrato con altre caratteristiche fondamentali del linguaggio. Aiuta invece a formalizzare l'idea di oggetti funzione che sono stati un linguaggio C++ per un bel po 'di tempo.

+0

Thx, il punto su "questo" è importante, non l'ho considerato. Lo prenderò in considerazione. – Zeks

+0

@Zeks yup. In passato ero 'boost :: function' felice ma poi me ne sono pentito. È una funzione che ha usi specifici ma IMO non dovrebbe essere la risposta predefinita ai problemi. –

+0

Btw, c'è qualche articolo sulle possibili insidie ​​quando si usa la funzione std/boost ::? C'è dell'altro che dover preoccuparsi di "questo"? – Zeks

1

Non vedo come si possa giungere alla conclusione che i puntatori di funzione rendono obsolete le classi base astratte.

Una classe, incapsula metodi e dati che si riferiscono ad esso.

Un puntatore a funzione è un puntatore a funzione. Non ha idea di un oggetto incapsulante, conosce solo i parametri passati ad esso.

Quando scriviamo le classi, stiamo descrivendo oggetti ben definiti.

I puntatori di funzione sono ottimi per un buon numero di cose, ma cambiare il comportamento di un oggetto non è necessariamente il pubblico di destinazione (anche se ammetto che potrebbero esserci delle volte in cui si vorrebbe farlo, ad esempio richiamate, come Doug.T cita).

Si prega di non confondere i due.

+0

Non sto dicendo che sono obsoleti. Solo che la funzione std :: può essere applicata per eseguire un lavoro un po 'simile. Sto chiedendo questo _because_ Non sono sicuro di dove siano i confini tra i due :) – Zeks