Puntatori a funzioni virtuali proprie in C++ "standard"

di il
4 risposte

Puntatori a funzioni virtuali proprie in C++ "standard"

Ciao Forum,

Mi sto arrovellando sulla seguente questione, senza riuscire a capire come si fa. Ho una certa classe "CListItem" che contiene un puntatore a un metodo virtuale di un'altra classe "CObjBase" e fin qui tutto OK, posso assegnare e deferenziare il puntatore. Ma se da "CObjBase" derivo una classe, in questa classe ridefinisco la funzione virtuale e tento di prendere l'indirizzo della funzione ridefinita, ovviamente il compilatore protesta perché la funzione cui sto cercando di puntare non è più una funzione della classe base ma di una da essa derivata. Accludo il codice così come lo sto provando.

Il mio obiettivo è poter chiamare da "CListItem" le funzioni virtuali ridefinite nelle classi derivate da "CObjBase"; questo tipo di problema inizia a mettere un po' alle corde la mia non eccelsa conoscenza del C++ quindi non so vagliare più di tanto i risultati che trovo in rete. Mi pare, ma solo mi pare di aver capito che il C++ 99 non ha i costrutti per affrontare questo problema e ho letto di un ente che si chiama "funzionoide" ma è implementato solo sul C++11. Orbene, ho letto anche che il supporto al C++11 non è consolidato in gcc e che ha ancora qualche bachetto. Inoltre, ma questa è una sorta di cilegina sulla torta, non mi piace l'overkilling e se anche gcc implementasse perfettamente il C++11 io ci vorrei ricorrere solo se la soluzione in C++ standard fosse poco elegante (compreso rendere friend le classi, cose che detesto ma in caso di necessità ovviamente farei). Se invece non c'è alternativa, copincollerò (perché temo che non mi sarà comprensibile) con le dovute modifiche quello che vorrete suggerirmi.

Come sempre grazie mille per ogni suggerimento

class  CListItem ;
class  CObjBase ;

// =====================================

class    CListItem
{
    public :

        void  (CObjBase::*funptr)(const int, const int) ;
} ;

// .....................................

class    CObjBase
{
    public :

        virtual void   function (const int a, const int b) { }
} ;

// .....................................

class    CObjDeri : public CObjBase
{
    public :

        void   function (const int a, const int b) { }
} ;

// =====================================

int     main ()
{
    CListItem      list_item      ;
    CObjBase       mainobj_base   ;
    CObjDeri       mainobj_deri   ;

    // OK

    (list_item.funptr) = &(mainobj_base.function) ;

    // Ovviamente dà errore :(

    (list_item.funptr) = &(mainobj_deri.function) ;

    // Fine

    return (0) ;
}

4 Risposte

  • Re: Puntatori a funzioni virtuali proprie in C++ "standard"

    Il gcc supporta pienamente il C++11, il C++14, e credo nell'ultimissima versione anche tuttol il C++17.
    A me pare comunque che tu voglia complicarti la vita.
    
    class  CListItem ;
    class  CObjBase ;
    
    
    class    CListItem
    {
        public :
    
            CObjBase* ptr_base;
    } ;
    
    // .....................................
    
    class    CObjBase
    {
        public :
    
            virtual void   function (const int a, const int b) { }
    } ;
    
    // .....................................
    
    class    CObjDeri : public CObjBase
    {
        public :
    
            void   function (const int a, const int b) { }
    } ;
    
    
    // =====================================
    
    int     main ()
    {
        CListItem      list_item      ;
        CObjBase       mainobj_base   ;
        CObjDeri       mainobj_deri   ;
    
        // OK
    
        list_item.ptr_base = &mainobj_base ;
        list_item.ptr_base->function(/* etc */ );
    
        list_item.ptr_base = &mainobj_base ;
        list_item.ptr_base->function(/* etc */ );
    
    
        // Fine
    
        return (0) ;
    }
    
  • Re: Puntatori a funzioni virtuali proprie in C++ "standard"

    Già... la soluzione era sotto il mio naso. Certo, tenere copia del puntatore in ogni elemento della lista dispiace al mio senso estetico ma pazienza, è decisamente una soluzione lineare e naturale. Grazie!
  • Re: Puntatori a funzioni virtuali proprie in C++ "standard"

    Comunque è possibile avere solo un puntatore per funzione virtuale, però comunque per invocare la funzione avrai bisogno di un elemento su cui invocare la funzione visto che la funzione è una funzione membro. Detto questo puoi fare cosi :
    
    #include <iostream>
    struct Base
    {
    	virtual void function(int a, int)
    	{
    		std::cout << "Base\n";
    	}
    };
    struct Derived:Base
    {
    	void function(int , int) override
    	{
    		std::cout << "Derived\n";
    	}
    }; 
    struct Derived1 :Base
    {
    	void function(int, int) override
    	{
    		std::cout << "Derived1\n";
    	}
    };
    template<class T,class F>
    struct VirtualPointer
    {
    	template <class... Args>
    	void call_function(T& element,Args... args)
    	{
    		(element.*func_ptr)(std::forward<Args>(args)...);
    	}
    	F func_ptr;
    };
    int main()
    {
    	Base b;
    	Derived derived;
    	Derived1 derived1;
    	VirtualPointer<Base, decltype(&Base::function)> a{ &Base::function };
    	a.call_function(b, 1, 2);
    	a.call_function(derived1, 1, 2);
    	a.call_function(derived, 1, 2);
    	return 1;
    }
    
    Se non hai la stretta necessità di avere solo un puntatore per funzione virtuale ti sconsiglierei di chiamare le funzioni virtuali in questo modo e molto più semplice e chiaro usare un vector<Base*> per avere una collezione di tutti i Derived su cui vuoi chiamare la funzione virtuale
  • Re: Puntatori a funzioni virtuali proprie in C++ "standard"

    Che meraviglia di soluzione... grazie mille anche a te. Spero di riuscire a fare cose simili un giorno.
Devi accedere o registrarti per scrivere nel forum
4 risposte