PDA

View Full Version : [C++]Funzione statica in una gerarchia di oggetti...


cionci
04-06-2003, 10:58
Ho bisogno di creare una gerarchia di oggetti... Questi oggetti devono contenere una funzione statica (mi serve statica perchè la devo lanciare come thread)...
Vorrei però che questa funzione sia anche virtuale e nell'oggeto base non venga implementata...
Faccio un esempio di quello che vorrei fare:

class A {
virtual static DWORD WINAPI ThreadFunction(LPVOID lpParameter) = 0;
public:
A();
HANDLE Start();
};

HANDLE A::Start()
{
return CreateThread(NULL, 10240, ThreadFunction, (LPVOID)this, 0, &threadID);
}

class B: public A {
virtual static DWORD WINAPI ThreadFunction(LPVOID lpParameter);
};

DWORD B::ThreadFunction(LPVOID lpParameter)
{
while(1) {
/*...*/
}
}

Il compialtore mi dice che non si può dichiarare una funzione statica come virtuale...e questo mi torna...di conseguenza bisogna fare in un altro modo...
Ora...io avevo pensato ad un modo per aggirare il problema...

class A {
static DWORD WINAPI ThreadFunction(LPVOID lpParameter);
virtual DWORD Thread() = 0;
public:
A();
HANDLE Start();
};

HANDLE A::Start()
{
return CreateThread(NULL, 10240, ThreadFunction, (LPVOID)this, 0, &threadID);
}

DWORD A::ThreadFunction(LPVOID lpParameter)
{
//In lpParameter passo il puntatore a this
return ((A*)lpParameter)->Thread();
}


class B: public A {
virtual DWORD Thread();
};

DWORD B::Thread()
{
while(1) {
/*...*/
}
}

Che ne dite ? E' una buona soluzione ? Ah...ovviamente bisognerà gestirsi l'accesso concorrente sui dati della classe...

ilsensine
04-06-2003, 12:19
Sì mi sembra buona

maxithron
04-06-2003, 12:25
Ma il linguaggio C sta per C..ionci? :D

Ottima idea!

cionci
04-06-2003, 12:36
Originally posted by "maxithron"

Ma il linguaggio C sta per C..ionci? :D
No è un definizione doppiamente ricorsiva...sta per C-on-C ;) :D :sofico:

cionci
04-06-2003, 12:37
Originally posted by "ilsensine"

Sì mi sembra buona
Ci sono modi alternativi ?

ilsensine
04-06-2003, 12:56
Originally posted by "cionci"


Ci sono modi alternativi ?
Niente che valga la pena di seguire. Tempo fa avevo fatto una cosa simile; avevo anche provato a lanciare il thread direttamente nel costruttore della classe base, ma non è possibilie in quanto non si ha ancora la visibilità delle funzioni virtuali delle classi discendenti.

cionci
04-06-2003, 12:59
Thanks...poi vi farò vedere il risultato... ;)

cionci
04-06-2003, 15:39
Ho un altro problema simile...

E per un singleton come faccio ? Non posso derivarlo...

class sing {
static sing*_inst;
protected:
sing() { Load(); };
public:
static sing* GetIstance();
virtual bool Load() = 0;
virtual bool GetParam(...); /*le ho messe solo per bellezza*/
virtual bool SetParam(...);
};

sing::_inst = NULL;

public A: public sing {
public:
virtual bool Load() { /*...*/ };
};

Ho fatto bene ? "A" mi sembra di poterlo trattare come un normale singleton, vero ?

cionci
04-06-2003, 15:44
No azz...non va bene la GetInstance...

sing* sing::GetInstance(){
if(_inst == NULL)
_inst = new sing;
return _inst;
}

Purtroppo non credo che ci siano vie alternative qui...

ilsensine
04-06-2003, 17:29
Qui non ti posso dire nulla, i singleton non esistono dalle mie parti...

/\/\@®¢Ø
05-06-2003, 12:53
Originally posted by "cionci"

Ho un altro problema simile...

E per un singleton come faccio ? Non posso derivarlo...

class sing {
static sing*_inst;
protected:
sing() { Load(); };
public:
static sing* GetIstance();
virtual bool Load() = 0;
virtual bool GetParam(...); /*le ho messe solo per bellezza*/
virtual bool SetParam(...);
};

sing::_inst = NULL;

public A: public sing {
public:
virtual bool Load() { /*...*/ };
};

Ho fatto bene ? "A" mi sembra di poterlo trattare come un normale singleton, vero ?

Non puoi chiamare un metodo virtuale nel costruttore, la costruzione dell'oggetto non e' ancora stata completata: oltre al fatto che il costruttore della classe derivata non e' stato ancora chiamato (e quindi rischieresti di operare su di un oggetto inconsistente) in generale ti troverai con un vtable incompleta (fai una prova con una classe base astratta e il g++ ti riportera' un "pure virtual method called" :eek: :D ). Se non ricordo male inoltre ogni classe derivata ha una copia dei campi statici ( sing::_inst e' diverso da A::_inst ) e quindi devi in ogni caso operare differentemente.
Come li vorresti utilizzare i due singleton ? (considerarli due distinti, considerarli uguali...)

cionci
05-06-2003, 18:03
Ti spiego quello che volevo fare....

Io volevo fare una classe base astratta per cui solo definendo la funzione Load la classe derivata era utilizzabile come singleton...

class A {
/*quello che ci dovrà essere*/
public:
static A *GetIstance();
};

class B: public A {
private:
B();
bool Load();
};

B::GetIstance()->(proprietà o metodi vari definiti in B);

/\/\@®¢Ø
05-06-2003, 20:51
Ma il metodo load dovrebbe impostare il campo inst? :confused:

Comunque potresti utilizzare qualcosa del genere


template <class T>
class singleton : public T
{
singleton(){}
static T* inst;
bool loaded;
public:
static void init()
{
if ( ! loaded )
{
loaded = true;
// oppure un qualsiasi altro metodo statico di T
inst = new T();
}
}

static T& instance()
{
return *inst;
}

static const T& instance() const
{
return *inst;
}

};

class A
{
protected:
A();
};

/* ... */

typedef singleton<A> sin;
sin::init(...);
sin::instance().something( ... );


Di brutto c'e' che il costruttore e' protected e non private, quindi la soluzione non e' perfetta, ( al piu' puoi sempre mettere il costruttore private e aggiungere friend class singleton<A> nella classe A).

cionci
06-06-2003, 02:52
Originally posted by "/\/\@®¢Ø"

Ma il metodo load dovrebbe impostare il campo inst? :confused:
Load dovrebbe servere a caricare (e ricaricare) i valori di alcune variabili membro dell'oggetto A...
Comunque la tua soluzione è interessante...magari l'unica cosa è che non obbligo ad implementare in A un metodo chiamato Load...