Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Wskaźniki na metody + dziedziczenie

Ostatnio zmodyfikowano 2010-09-16 12:38
Autor Wiadomość
DejaVu
Temat założony przez niniejszego użytkownika
Wskaźniki na metody + dziedziczenie
» 2010-09-16 01:29:18
Mam następujący kod:
C/C++
#include <cstdio>

class CBla
{
public:
    int licznik;
    CBla()
        : licznik( 0 )
    {
    }
   
    typedef int( CBla::* Method_CommandT )( int a, int b );
    int dodaj( int a, int b )
    {
        licznik++;
        return a + b + licznik;
    }
   
    int odejmij( int a, int b )
    {
        return a - b;
    }
   
   
}; //class CBla
class CBle
    : public CBla
{
public:
    int dodajNowe( int a, int b )
    {
        licznik += 10;
        return a + b + licznik;
    }
};


class CXXX
{
public:
    void uruchom( CBla * ptr, CBla::Method_CommandT uruchom = NULL )
    {
        printf( "%d \n",( ptr->* uruchom )( 1, 2 ) );
    }
};

int main()
{
    CBla klasa;
    CBla klasa2;
    CBle klasa3;
    CXXX ble;
    ble.uruchom( & klasa, & CBla::dodaj );
    ble.uruchom( & klasa, & CBla::dodaj );
    ble.uruchom( & klasa, & CBla::dodaj );
    ble.uruchom( & klasa2, & CBla::dodaj );
    ble.uruchom( & klasa, & CBla::dodaj );
    ble.uruchom( & klasa3, & CBle::dodajNowe ); //INFO: tu wali błędem
    // ble.uruchom(&klasa3,( (CBla::*) (int, int) )(&CBle::dodajNowe));
   
    return 0;
}
Log kompilacji:
|In function 'int main()':|
56|error: no matching function for call to 'CXXX::uruchom(CBle*, int (CBle::*)(int, int))'|
39|note: candidates are: void CXXX::uruchom(CBla*, int (CBla::*)(int, int))|
||=== Build finished: 1 errors, 0 warnings ===|

Czy ktoś wie jak rozwiązać powyższy problem?

/edit:
W sumie sam sobie poradziłem ;p
C/C++
ble.uruchom( & klasa3,( int( CBla::* )( int, int ) )( & CBle::dodajNowe ) );
Niemniej jednak jest jeszcze jeden problem - jak zrobić to bez konieczności wpisywania rzutowania w poprawionym wierszu? Może być w innym miejscu, byle nie przy podawaniu metody.
P-22026
Elaine
» 2010-09-16 09:21:39
Może po prostu trzeba olać wskaźniki na metody i użyć jakiejś implementacji delegatów - one nie mają takich problemów, są bardziej ogólne, w dodatku niektóre implementacje są szybsze od wskaźników na metody (vide FastDelegate pod kompilatorem Microsoftu i Intela)?

Pluć błędem pluje, bo taka konwersja zwyczajnie naruszyłaby typizację - istnieje niejawna konwersja ze wskaźnika na metodę klasy bazowej na wskaźnik na metodę klasy pochodnej (bo klasa pochodna ma metody klasy bazowej), ale już nie w drugą stronę - wskaźnik może przecież wskazywać na metodę, której w klasie bazowej po prostu nie ma.

Chamskie rzutowanie powoduje, że kod się kompiluje, a nawet działa pod większością kompilatorów, ale mimo tego takie coś standard określa jako niezdefiniowane zachowanie - i słusznie, w końcu ponoć C++ ma silną typizację, a ona nie służy do tego, by ją omijać.

Jeśli chodzi o rozwiązanie - najlepszym są wspomniane na początku delegaty, dobrym pomysłem jest też zastąpienie tego polimorfizmem. Jeśli jednak uparłeś się na wskaźniki na metody, to można zrobić niewielki wrapper, który po cichu tę konwersję przeprowadzi, na przykład:
C/C++
template < typename T >
void run( T * object, int( T::* mpf )( int, int ) )
{
    uruchom( object, reinterpret_cast < int( CBla::* )( int, int ) >( mpf ) );
}
P-22029
DejaVu
Temat założony przez niniejszego użytkownika
» 2010-09-16 10:22:00
Ok, dzięki - podobne rozwiązanie zrobiłem sobie w nocy. Zastanawiałem się tylko czy da radę to zrobić bez szablonu lub bez jawnego podawania nazwy klasy przy wywołaniu metody, tylko po to by wykonać rzutowanie.

/edit:
Przeglądałem też wczoraj boost::bind oraz boost::function, ale z jakiegoś obszernego artykułu wynikło, iż jest to wolne rozwiązanie w stosunku do innych dostępnych. Ponadto nie udało się uzyskać tego efektu, który chciałem (również byłoby potrzebne rzutowanie).
P-22030
Elaine
» 2010-09-16 11:11:34
Może FastDelegate zamiast boosta?
P-22031
DejaVu
Temat założony przez niniejszego użytkownika
» 2010-09-16 12:38:57
Nom w sumie ciekawa biblioteka. W moim rozwiązaniu brakowało mi patentu z dedukcją parametrów:
C/C++
template < class Klasa >
void funkcja( Klasa * ptr )
{
    printf( "%p", ptr );
}
//...
Klasa klasa;
funkcja( & klasa );
Przykład trochę przygłupawy, ale można fajne efekty dzięki temu otrzymać.
P-22032
« 1 »
  Strona 1 z 1