Torna indietro   Hardware Upgrade Forum > Software > Programmazione

PC Specialist Lafité 14 AI AMD: assemblato come vuoi tu
PC Specialist Lafité 14 AI AMD: assemblato come vuoi tu
Il modello "build to order" di PCSpecialist permette di selezionare una struttura base per un sistema, personalizzandolo in base alle specifiche esigenze con una notevole flessibilità di scelta tra i componenti. Il modello Lafité 14 AI AMD è un classico notebook clamshell compatto e potente, capace di assicurare una elevata autonomia di funzionamento anche lontano dalla presa di corrente
Recensione Nothing Phone 4(a): sempre iconico ma ora più concreto
Recensione Nothing Phone 4(a): sempre iconico ma ora più concreto
Nothing con il suo nuovo Phone 4(a) conferma la sua identità visiva puntando su una costruzione che nobilita il policarbonato. La trasparenza resta l'elemento cardine, arricchita da una simmetria interna curata nei minimi dettagli. Il sistema Glyph si evolve, riducendosi nelle dimensioni ma aumentando l'utilità quotidiana grazie a nuove funzioni software integrate e notifiche visive. Ecco tutti i dettagli nella recensione completa
Corsair Vanguard Air 99 Wireless: non si era mai vista una tastiera gaming così professionale
Corsair Vanguard Air 99 Wireless: non si era mai vista una tastiera gaming così professionale
Nelle ultime settimane abbiamo provato la Corsair Vanguard Air 99 Wireless, una tastiera tecnicamente da gaming, ma che in realtà offre un ampio ventaglio di possibilità anche al di fuori delle sessioni di gioco. Flessibilità e funzionalità sono le parole d'ordine di una periferica che si rivolge a chi cerca un prodotto capace di adattarsi a ogni esigenza e ogni piattaforma
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 12-11-2009, 23:56   #1
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
[C++] Ricordatemi una keyword esotica!

Salve,
ho fatto un magheggio di questo tipo:

Codice:
class Kernel : 
    public Task::ListenerImpl<ValueQuery>, 
    public Task::ListenerImpl<SomeTask>, 
    public Task::ListenerImpl<SomeOther>
Dove ListenerImpl<T> eredita Listener.

Ora, tutto funziona bene, e posso fare dei metodi callback distinti per ogni tipo;
però: se uso this come Listener*, il cast è giustamente ambiguo perchè Listener è ereditato ben 3 volte!

Mi ricordo che c'era una keyword assurda ed esotica che faceva ereditare le superclassi una ed una sola volta... come Listener in questo caso.

La sapete? O almeno ditemi cosa potrei cercare su Google
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 13-11-2009, 15:43   #2
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Mi dà l'idea che mi ricordavo male

Vabbè alla fine basta fare il cast ad uno dei 3 tipi...
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 13-11-2009, 21:10   #3
wizard1993
Senior Member
 
L'Avatar di wizard1993
 
Iscritto dal: Apr 2006
Messaggi: 22462
che io sapessi c'era un "giochino" per evitare l'inclusione ciclica dei file sorgente, ma nulla più
__________________
amd a64x2 4400+ sk939;asus a8n-sli; 2x1gb ddr400; x850 crossfire; 2 x western digital abys 320gb|| asus g1
Se striscia fulmina, se svolazza l'ammazza
wizard1993 è offline   Rispondi citando il messaggio o parte di esso
Old 13-11-2009, 23:20   #4
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da Tommo Guarda i messaggi
Salve,
ho fatto un magheggio di questo tipo:

Codice:
class Kernel : 
    public Task::ListenerImpl<ValueQuery>, 
    public Task::ListenerImpl<SomeTask>, 
    public Task::ListenerImpl<SomeOther>
Dove ListenerImpl<T> eredita Listener.

Ora, tutto funziona bene, e posso fare dei metodi callback distinti per ogni tipo;
però: se uso this come Listener*, il cast è giustamente ambiguo perchè Listener è ereditato ben 3 volte!

Mi ricordo che c'era una keyword assurda ed esotica che faceva ereditare le superclassi una ed una sola volta... come Listener in questo caso.

La sapete? O almeno ditemi cosa potrei cercare su Google
Codice:
template <typename T>
class ListenerImpl : public virtual Listener
{
/* */
};
o giu' di li'.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele

Ultima modifica di marco.r : 13-11-2009 alle 23:23.
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 14-11-2009, 19:56   #5
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Si era proprio quello grazie mille

Però ora che ci ho provato, l'unificare la classe base rende impossibile distinguere i metodi di callbacks in base al tipo... quindi mi sembra sensato che l'utente deve specificare a quale "parte" del listener mandare il messaggio.
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2009, 11:14   #6
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Boh...a me una cosa del genere puzza un po'. Non è meglio estrarre un'interfaccia comune alle tre classi (Listener appunto) e poi aggiungere un membro di tutte e tre all'interno di Kernel ? Solo vedendo due righe di codice non riesco proprio a vederci una relazione di ereditarietà...

Ultima modifica di cionci : 15-11-2009 alle 11:17.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2009, 13:49   #7
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Beh, la classe Kernel in realtà è solo un test, è una "classe ipotetica" che potrebbe richiedere un callback di completamento di un Task...

ho pensato che in questo modo venisse "stiloso" perchè, dato che per usare l'interfaccia Task c'è bisogno di farne una sottoclasse, usare un elenco di Listener<T> permette di avere un metodo di callback per ogni tipo, con il puntatore passato già del tipo giusto, tipo nell'esempio di prima:
Codice:
taskCompleted( ValueQuery* );
taskCompleted( SomeTask* );
taskCompleted( SomeOther* );
etc...
Poi certo si può anche ereditare il metodo generico che passa Task* ma poi devi procedere autonomamente ai cast (spesso molto poco "solidi")...
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2009, 16:15   #8
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Imho non si usa l'ereditarietà per risparmiare la scrittura di alcuni metodi, si usa quando c'è una relazione fra classe base e derivata.
In questo caso non mi sembra che ci sia, sarebbe come ereditare una classe macedonia dalle classi pera, mela e banana...
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2009, 16:38   #9
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Non capisco la critica onestamente

La relazione in questo caso è solo che devo offrire all'utente un modo per ricevere un callback quando il Task (che è asincrono!) viene completato... non vedo quale altro modo più semplice ci sia se non permettere all'user di ereditare il Listener che preferisce...

E poi non è che l'ereditarietà serve solo quando A is B eh...
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2009, 17:40   #10
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Se ne hai voglia ricapitolami bene la situazione...non sto dicendo che l'unica relazione che si può esprimere con l'ereditarietà sia a is b, sto dicendo che molte volte in cui si fanno questi pastrocchi (una ereditarietà triplada classi non astratte per me lo è) non è necessario.
Vediamo cosa ho capito: ci sono questi Listener che sono delle classi che si aspettano di ricevere un messaggio di completamento da una operazione asincrona.
Vuoi che Kernel abbia la possibilità di stare in ascolto su tre tipi di eventi distinti. Ovviamente mi immagino che dovrai registrare questi listener presso l'operazione asincrona...
Premetto che sto derivando questi discorsi dai nomi delle classi e dalla semplice intestazione che hai proposto, quindi posso benissimo essere smentito.
Tu vuoi registrare direttamente un'istanza di Kernel presso gli eventi asincroni in modo che venga chiamato direttamente un metodo della classe.
Prima di tutto mi immagino che il compito principale della classe Kernel, dato il nome, non sia di ricevere le notifiche, ma di fare molte altre cose, fra cui la ricezione delle notifiche. Derivando una classe se ne caratterizza il comportamento, quindi se il compito principale di Kernel non è ricevere le notifiche per me l'hai caratterizzata male.

Io separerei la classe Kernel dalla ricezione delle notifiche, creerei una classe KernelListener, addirittura una per ogni tipo di notifica o un template, che prende come parametro l'istanza della classe kernel e si occupa di eseguire le operazioni necessarie su Kernel al momento della ricezione dell'evento.

Ad esempio:

Codice:
template <typename T>
class KernelListener: public ListenerImpl<T>
{
private:
   Kernel *kernel;
public:
   KernelListener(Kernel *k):kernel(k){};
   virtual void taskCompleted(T *info)
   {
       ListenerImpl<T>::taskCompleted(info);
       kernel->notifyTaskCompleted(info);
   }
};


class Kernel
{
private:
   KernelListener<ClassA> listener1;
   KernelListener<ClassB> listener2;
   KernelListener<ClassC> listener3;
public:
   void registerListener(AsyncEvent1 evt1, AsyncEvent2 evt2, AsyncEvent3 evt3)
   {
      evt1.register(listener1);
      evt2.register(listener2);
      evt3.register(listener3);
   }

   void notifyTaskCompleted(ClassA info);
   void notifyTaskCompleted(ClassB info);
   void notifyTaskCompleted(ClassC info);
};
Questa sopra per me è la corretta implementazione di ciò che vuoi fare, certo c'è da scrivere qualche linea di codice in più, ma non c'è alcuna forzatura.

Ultima modifica di cionci : 15-11-2009 alle 17:43.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2009, 18:19   #11
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Grazie della spiegazione

Allora; premetto che ci hai preso sulle funzioni di più o meno tutte le classi dal loro nome
Tuttavia Kernel da quando ho iniziato a "smanettare" con i Task è rimasto privo di funzioni proprie se non lanciare il task iniziale, quindi per evitare forzature pensavo proprio di toglierlo.
E poi ListenerImpl<T> in realtà è una classe astratta formata da 2 metodi... in pratica è un'interfaccia generica stile Java, e per questo non mi sembrava brutto più di tanto ereditarne più d'una (caso comunque molto raro in teoria).

Codice:
		class Listener : public BaseObject
		{
		public: 
			virtual void taskCompleted( Task* t )=0;
		};

		template <class T>
		class ListenerImpl : public Listener
		{
		public:
			void taskCompleted( Task* t )
			{
				taskCompleted( static_cast<T*>(t) );
			}

			virtual void taskCompleted( T* t )=0;

		};
Comunque, la faccenda dei listeners è dovuta al fatto che stavo sperimentando un'ipotetica "libreria di threading" giusto per imparare i concetti base; quindi Listener appartiene alla libreria, ma deve essere usato all'esterno e quindi io sto fornendo solamente un'interfaccia.
Poi ovvio che sta cosa non sarà mai usata da nessuno, ma lo scopo è didattico

La tua idea mi piace, il fatto è che non capisco bene come potrei implementarla; gli eventi sono sostanzialmente *lo stesso* cioè Task Complete; dal Dispatcher di questi famosi task posso ottenere giusto questa informazione, e tratto qualsiasi listener come Listener, il tipo più astratto... non sono a conoscenza del tipo del task che viene completato, dato che il tipo è esteso dall'user.
Quello che cambia è il <T> del Listener passato al Task, tipo
Codice:
dispatcher->schedule( new TaskQualsiasi( (ListenerImpl<TaskQualsiasi>*)this));
che in realtà tramite i templates viene creato e passato proprio dall'user; dispatcher si limita a chiamare Listener->taskCompleted() che poi viene girato tramite overriding al tipo giusto.
Per cui, data la scarsissima riflessività del C++ non saprei bene come legare una sottoclasse "sconosciuta" di Task ad un dato callback se non domandando all'user di specificare tutte quante le chiamate come nel tuo esempio... cosa che almeno imo, anche se più corretta non vale troppo la candela... tantopiù che il template cast all'assegnazione rimarrebbe in ogni caso.

O altrimenti levo tutto, metto un bel campo void* userData e lascio tutto all'esterno
__________________
*ToMmO*

devlog | twitter

Ultima modifica di Tommo : 15-11-2009 alle 18:23.
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2009, 18:51   #12
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Quindi in pratica il problema è passare dei dati al listener mantenendo la genericità dello stesso...
Fatti una classe base astratta dei valori passati a listener !!!
L'utente per passare un dato dovrà implementare un'interfaccia. In questo modo potrai gestire tutto con la classe astratta Inoltre potrai anche avere il listener sotto forma di classe normale e non template.
cionci è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


PC Specialist Lafité 14 AI AMD: assemblato come vuoi tu PC Specialist Lafité 14 AI AMD: assemblat...
Recensione Nothing Phone 4(a): sempre iconico ma ora più concreto Recensione Nothing Phone 4(a): sempre iconico ma...
Corsair Vanguard Air 99 Wireless: non si era mai vista una tastiera gaming così professionale Corsair Vanguard Air 99 Wireless: non si era mai...
Ecovacs DEEBOT T90 PRO OMNI: ora il rullo di lavaggio è ampio Ecovacs DEEBOT T90 PRO OMNI: ora il rullo di lav...
Recensione Samsung Galaxy S26 Ultra: finalmente qualcosa di nuovo Recensione Samsung Galaxy S26 Ultra: finalmente ...
Epic non ha alcuna intenzione di smetter...
MacBook Neo: la scommessa economica di A...
Addio elio-3? La scoperta cinese che pot...
OpenAI punta a 8.000 dipendenti entro il...
Democratici all'attacco di NVIDIA: l'acc...
Elon Musk ha annunciato Terafab: fabbric...
Tutte le migliori offerte Amazon del wee...
Assassin's Creed: iniziate le riprese de...
TV 4K in super offerta: 75'' Mini-LED Hi...
iPad Air in offerta: 11'' con chip M3 a ...
Garmin Instinct 2X Solar Tactical a 259€...
Crimson Desert: Intel ha cercato di coll...
MacBook Air M4 da 899€ su Amazon, ma non...
POCO X8 Pro e Pro Max 12/512GB -23% su A...
Twitter, la verità dietro il crol...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 17:39.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v