Visualizzazione dei risultati da 1 a 6 su 6

Discussione: [C++] Classi derivate

  1. #1
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177

    [C++] Classi derivate

    Quello che ho trovato cercando sia nel forum che in internet non mi ha risolto i problemi, quindi mi permetto di aprire un nuova discussione.

    Il problema è che mi serve dichiarare all'inizio un puntatore alla classe base, e successivamente, farlo puntatore (new...) ad una classe derivata.
    E questo è a posto.
    L'overriding delle funzioni dovrebbe essere a posto.
    Che crea problemi è se nella classe derivata implemento unafunzione che non c'è nella classe base, e tutto si pianta.
    Ho trovato in giro di mettere using ClasBase::xxxx, ma non risolve il problema, o ho sbagliato a usarlo.

    Ecco il codice che riproduce il problema

    classi.h
    codice:
    #ifndef CLASSI_H
    #define CLASSI_H
    
    class ClasBase
    {
      public:
        ClasBase();
        virtual ~ClasBase();
    
        virtual void pippo();
    };
    
    class ClasDerivata:public ClasBase
    {
      public:
        ClasDerivata();
        ~ClasDerivata();
    
        void pippo();
        void pippo2();
    };
    
    
    #endif // CLASSI_H
    classi.cpp
    codice:
    #include "classi.h"
    #include <iostream>
    
    using namespace std;
    
    ClasBase::ClasBase()
    {
      cout<<"\n"<<__func__;
    }
    
    ClasBase::~ClasBase()
    {
      cout<<"\n"<<__func__;
    }
    
    void ClasBase::pippo()
    {
      cout<<"\nClasBase::"<<__func__;
    }
    
    ClasDerivata::ClasDerivata():ClasBase()
    {
      cout<<"\n"<<__func__;
    }
    
    void ClasDerivata::pippo()
    {
      cout<<"\nClasDerivata::"<<__func__;
    }
    
    void ClasDerivata::pippo2()
    {
      cout<<"\nClasDerivata::"<<__func__;
    }
    
    ClasDerivata::~ClasDerivata()
    {
      cout<<"\n"<<__func__;
    }
    main.cpp
    codice:
    #include <iostream>
    #include <stdlib.h>
    #include "classi.h"
    
    using namespace std;
    
    
    int main()
    {
        cout << "Hello world!" << endl;
        ClasBase base;
        system("pause");
        ClasBase* classe;
        classe=new ClasBase;
        classe->pippo();
        delete(classe);
        classe=new ClasDerivata;
        system("pause");
        classe->pippo();
        classe->ClasBase::pippo();
        classe->pippo2();//mettendo il commento a questa riga il programma fila liscio
        delete(classe);//richiama correttamente i due distruttori. Se però metto il commento a questa riga, alla fine del programma vedo richiamato solo il distruttore di ClasBase, corretto?
        system("pause");
        return 0;
    }
    Perchè non riesco a far funzionare la funzione "pippo2"?

    L'errore del compilatore è il seguente

    ||=== Build: Debug in Classi derivate (compiler: GNU GCC Compiler) ===|
    C:\C++\Classi derivate\main.cpp||In function 'int main()':|
    C:\C++\Classi derivate\main.cpp|21|error: 'class ClasBase' has no member named 'pippo2'|
    ||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

  2. #2
    Tramite un puntatore a classe base puoi invocare solo i metodi dichiarati nella classe base (eventualmente ridefiniti nella classe derivata). Per invocare un metodo definito solo nella classe derivata da un puntatore a classe base servirebbe il cosiddetto "late binding", che in C++ non esiste; puoi simulare questo comportamento tramite un dynamic_cast a classe derivata.
    Amaro C++, il gusto pieno dell'undefined behavior.

  3. #3
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Mi pare che questa soluzione non sia esente da rischi, almeno, da quanto letto in giro (v. ad esempio https://it.wikipedia.org/wiki/Dynamic_cast), anche se sinceramente non riesco a comprenderli, e soprattutto che appesantisca il codice.
    Mi viene in mente che una alternativa allora possa essere la seguente, ma anche qui, data la scarsa esperienza, chiedo a voi se è logica come soluzione o se sarebbe "cattiva progettazione del codice".

    codice:
    class ClasseBase
    {
      public:
        ClasseBase();
        virtual ~ClasseBase();
      //quanto altro necesario
    }
    
    class ClasseDerivata1:public ClasseBase
    {
      public:
        ClasseDerivata1();
        ~ClasseDerivata1();
      //quanto altro necesario
    }
    
    class ClasseDerivata2:public ClasseBase
    {
      public:
        ClasseDerivata2();
        ~ClasseDerivata2();
      //quanto altro necesario
    }
    
    class ClasseCornice
    {
      public:
        ClasseCornice();
        ~ClasseCornice();
    
      private:
        ClasseBase* mBase;
        ClasseDerivata1* mDerivata1;
        ClasseDerivata2* mDerivata2;
        //metodi che gesticono la creazione/distruzione in base alle esigenze del codice, in modo che resti sempre e solo una sola istanza di uno degli oggetti gestiti
        //da ClasseCornice.
    
    }
    La cosa però potrebbe tornare utile anche se volessi fare un confronto tra mDerivata1 e mDerivata2, per esempio, corretto?
    Mi spiego: mDerivata1 potrebbe gestire una serie di dati generati da una funzione, y=f(x).
    mDerivata2, gestirebbe una cosa simile, ma la funzione, potrebbe cambiare, y=g(x), perchè legate, per quello che mi serve, a disposizioni di normativa che variano.
    Nel caso volessi realizzare un grafico che plotti le due funzioni per avere un confronto, ClasseCornice dovrebbe permettermelo, coi dovuti "metodi".
    Corretto?

    Grazie.

  4. #4
    Onestamente non riesco a capire neanche lontanamente di che stai parlando... fornisci casi d'uso concreti.

    Comunque, l'assenza del late binding di solito non è una grossa limitazione, perché se devi agire indifferentemente alla stessa maniera su due classi derivate allora chiami il metodo virtuale tramite puntatore alla classe base, se invece devi chiamare specificamente un metodo della classe derivata devi sapere necessariamente su che classe stai operando, per cui puoi fare il dynamic_cast e quindi richiamare il metodo.
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Intanto grazie infinite per il tempo che mi stai dedicando!!!!!

    Quote Originariamente inviata da MItaly Visualizza il messaggio
    Onestamente non riesco a capire neanche lontanamente di che stai parlando... fornisci casi d'uso concreti.
    Questa è la frase che mi ha acceso il campanello d'allarme (presa da =qui):
    Si tenga presente che affinché il costrutto dynamic_cast lavori correttamente è necessario che il supporto RTTI del compilatore sia attivo (spesso, nella produzione del firmware, si sceglie di non attivare RTTI poiché questa funzionalità assorbe una quantità di risorse non trascurabile).

    Se questo non è vero, nel senso che è magari una informazione "vecchia", allora procedo in questo modo.

    Il problema concreto è il seguente: la determinazione dell'azione sismica varia/evolve con l'evolvere della normativa e con il sito in cui sorge la costruzione (più altri fattori, ma per adesso bastano questi).
    Per gestire il sito, pensavo quindi creo una classe base che raccoglie le informazioni che sono "normativa indipendenti" come indirizzo, quota sul livello del mare, latitudine, longitudine, ecc.
    Da questa poi derivo una classe specifica per ogni normativa, in cui raccolgo le informazioni specifiche di quella normativa (ad esempio, quella attuale definisce dei parametri specifici di pericolosità sismica del sito)

    Avremo quindi
    codice:
    class Base
    {
      //indirizzo, altitudine, ecc, "normativa indipendenti"
      //metodi per gestire queste informazioni
      //distruttore virtuale
    }
    
    class Normativa1:public Base
    {
      //informazioni aggiuntive, come ad esempio pericolosità sismica del sito
      //metodi per gestire queste informazioni
      setPericolosita(param1, param2, ecc);
    }
    
    class Normativa2:public Base
    {
      //informazioni aggiuntive, come ad esempio pericolosità sismica del sito
      //metodi per gestire queste informazioni
      setPericolosita(param3, param4, ecc);
    }
    Se il nome del metodo setPericolosita è uguale nelle due classi derivate, i parametri sono di tipo diverso (nella fattispecie sono delle enum e delle struct create per ciascuna normativa, in quanto specifiche per ciascuna di esse).
    Ecco da dove nasce tutto il problema.

    Tralasciamo per ora il problema ipotizzato del confronto su grafico, che per genera solo confusione, limitiamoci alla possibilità di partire:
    • da un puntatore a una classe base,
    • creare un'istanza dell'oggetto ad una classe derivata in base alla normativa scelta,
    • accedere ai metodi della classe derivata senza dover definire il corrispettivo metodo virtuale nella classe base.


    Spero di aver chiarito il problema.

    Grazie

  6. #6
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Capito (spero...) dynamic_cast, su un singolo puntatore, mi viene il seguente dubbio, che non riesco a risolvere.

    Poniamo di aver creato ClasseBase, e da essa abbiamo derivato ClasseDerivata1, ClasseDerivata2, ClasseDerivata3, ecc..

    Poniamo di avere

    vector<ClasseBase*> vettore;

    è possibile aggiungere elementi al vector di tipo diverso, cioè ad esempio, il primo elemento di tipo ClasseDerivata2, il secondo elemento di tipo ClasseDerivata1, ecc?

    Quanto ho trovato in giro, mi sembra che non mi dia questa possibilità, cioè, tutti gli elementi del vector devono essere tutti dello stesso tipo della classe derivata, e per di più, devo operare su un secondo vector, cioè ci sarà vettore2 i cui elementi saranno tutti del tipo di una delle classi derivate ottenuti tramite dynamic_cast.

    Grazie

    P.S. nella fattispecie il problema sorge nel caso di sezioni composte, cioè date dalla somma di sezioni diverse...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.