Classi derivate

Buongiorno a tutti,

Stavo facendo degli esperimenti con le classi derivate, ho visto che il core di arduino ne fà uso, pertanto ho pensato che si potessero utilizzare anche normalmente negli sketch.
Ho fatto un esperimento, creando una classe base 'animale' e provando a crearne una derivata 'cane' ma ottengo un errore in compilazione.
Allego sorgenti delle classi

animale.h

class animale
{
private:

public:
	animale();
	virtual ~animale();
	void chiama();
        virtual int zampe();
};

animale.cpp

#include "animale.h"

animale::animale()
{
	// TODO Auto-generated constructor stub
}

animale::~animale()
{
	// TODO Auto-generated destructor stub
}

void animale::chiama()
{
  // chiama l'animale
}

cane.h

#include "animale.h"

class cane: public animale
{
private:

public:
	cane();
	virtual ~cane();
        int zampe();
};

cane.cpp

#include "cane.h"

cane::cane()
{
	// TODO Auto-generated constructor stub
}

cane::~cane()
{
	// TODO Auto-generated destructor stub
}

int cane::zampe()
{
  return 2;
}

L'errore che ritorna è :
animale.cpp.o:(.rodata._ZTV7animale+0x8): undefined reference to `animale::zampe()'

Mi è sfuggito qualcosa ?

In animale.h hai una funzione
virtual int zampe();
che non è implementata, se non vuoi implementarla devi trasformare la classe animale in astratta (non potrai istanziarla)

Ciao

Già , ma non mi pare che ci sia modo esplicito di creare una classe astratta.

dichiarando invece

virtual int zampe() = 0 ;

compila correttamente ma non ottengo quello che voglio, ovvero vorrei che il compilatore si incatsasse se dichiaro una classe derivata che non implementa una funzione prevista nella classe base ma non implementata (esattamente il concetto di una classe astratta insomma).

Con
virtual int zampe() = 0 ;
la classe diventa astratta, non devi scrivere abstract come in altri linguaggi di programmazione.
Il compilatore non ti da errori perché probabilmente ottimizza il codice e non compila le classi non utilizzate, se provi ad aggiungere:

cane c;
c.zampe();

vedrai che se non è implementata la funzione zampe e nella classe base è definita come una funzione virtuale pure (con =0) ti darà sicuramente errore

Si esattamente.

Ora il cerchio si chiude.

Praticamente dichiarando un metodo virtual = 'qualcosa' la classe diventa astratta e funziona tutto regolarmente come dovrebbe essere.
Ma a questo punto mi domando, se dichiarando una funzione di qualsiasi tipo (anche void) in questa maniera :

virtual animale.zampe() = 'qualcosa';

sono comunque obbligato a reimplementare quella funzione nella classe derivata , e alla stessa maniera non posso instanziare la classe base, a che cavolo serve mettere = 'qualcosa' ????

Non esiste un "= qualcosa", per dire al compilatore che la funzione è virtuale pura, che comporta che la classe sarà astratta, bisogna scrivere ad esempio

virtual void zampe() = 0;

il tipo e il nome della funzione non hanno importanza, possono essere come desideri, l'importante è la keyword "virtual" e "=0" per rendere la funzione virtuale pura.

Avere classi astratte è molto utile, senza bisogno che scrivo troppo su internet trovi molto materiale sulla programmazione ad oggetti

Ciao

Non puoi instanziare la classe base ma tramite i puntatori puoi trattare un oggetto derivato (es. cane) come un oggetto base (es. animale)
Per farti capire l'utilità, se hai uno zoo e vuoi far la conta delle zampe non devi gestire in modo particolare tutti gli animali ma puoi semplicemente fare affidamento sul fatto che tutti gli animali hanno un metodo zampe() come definito nella classe animale e fare qualcosa tipo:

cane c;	
int totZampe = 0;
animale *a; // animale può puntare ad un cane o ad un gatto (se deriva da animale)
a = &c;   // in questo caso puntiamo ad un cane
totZampe += a->zampe();  // l'istruzione è la solita sia che il puntatore "a" punta ad un cane o un gatto

ciao

Non fraintendere, non metto in discussione l'utilità delle classi astratte , a dimostrazione lo è il fatto che le stò usando!

Quello che non avevo capito era che come hai detto tu nell'intervento precedente non può essere :

virtual int zampe() = 'qualcosa';

ma deve essere proprio :

virtual int zampe() = 0;

A questo punto l'unica cosa oggettivamente sindacabile è la sintassi poco intuitiva, ma se alla fine quello deve essere, quello sarà!
avrei preferito il qualificatore abstract a livello di classe... ma sono gusti miei personali...

Quello che avevo erroneamente capito è che con = 0 si andasse ad impostare il valore ritornato dalla chiamata a quel metodo qualora non fosse stato reimplementato esplicitamente dalla classe derivata

Sì, in effetti la sintassi del C++ per indicare che una funzione è pure virtual è decisamente pessima :wink:

Solo una precisazione (se quanto sto per dire ti è già chiaro, ingoralo :slight_smile: ). Il fatto di avere un metodo virtual non rende astratta una classe. La parola chiave "virtual" attiva il meccanismo del polimorfismo.
Una classe è astratta quando ha almeno un metodo astratto (cioè dichiarato con la convenzione virtual / = 0).

Grazie , sia a tuxduino che a flz47655.

Le cose quando sono giuste e ben spiegate non sono mai superflue, e pertanto non vanno ignorate!
:wink:

Non bisogna mai perdere di vista il fatto che un forum non è un call-center di assistenza, quello che abbiamo dibattuto può essere d'aiuto anche per altri, non solo fine alla risoluzione del mio specifico problema.
8)

1