Newsgroup: it.comp.lang.c++
Titolo: Problema di link con classe derivata...

Ho una classe astratta e una derivata.
Se richiamo la funzione virtuale da un oggetto della classe astratta cerca
il codice della funzione anche nella classe astratta e non capisco il
perche'... ecco un esempio semplice:
==================
// --- Base.h ---
class Base
{
public:
  virtual void fun();
};
// --- Derived.h ---
#include <iostream.h>
#include "Base.h"
class Derived: public Base
{
public:
  void fun();
};
// --- Derived.cpp ---
#include "Derived.h"
void Derived::fun()
{
  cout << "Dentro Derived" << endl;
}
// --- main.cpp ---
#include <iostream.h>
#include "Derived.h"
void main()
{
  Derived D;
  D.fun();
}
==================
Non capisco quale sia il problema...
Compilando con:
  bcc32 -c Derived.cpp
  bcc32 main.cpp Derived.obj
Mi da questo errore:
  Error: Unresolved external 'Base::fun()' referenced from F:\PROGS\MAIN.OBJ
Deve essere qualcosa di semplice ma non capisco cosa...

};
In questo caso hai dichiarato fun() come una normale funzione
membro; se intendevi dichiararla solo in modo formale e con
l'idea di obbligare tutte le derivate a creare una propria
versione dovevi usare la dichiarazione di funzione virtuale pura:
   class Base
   {
     public:
       virtual void fun() = 0;
   };
In questo caso informi il compilatore che Base::fun() non
esiste e rende Base una Abstract Base Class ovvero una
classe di cui non possono esistere oggetti.
Questa dichiarazione inoltre permette al compilatore di
darti una mano a trovare errori di logica nel programma
(ad esempio tentativi di creare oggetti di tipo Base o
o anche discendenti da Base ma che non definiscono un
metodo fun()).
Dichiarando una funzione membro normale il compilatore si
aspetta che da qualche parte tu definisca Base::fun e quindi
si arrabbia quando dovendo trascrivere l'indirizzo di questa
funzione nella VMT della classe base non ne trova una
implementazione disponibile.
HTH
Andrea

 classe di cui non possono esistere oggetti.
Ho fatto una prova... senza dichiararla pura il compilatore creo lo stesso
l'oggetto sebbene teoricamente sia astratto.

> Tutto risolto... dovevo dichiarare la funzione membro pura.
Virtuale pura

 };
DEVE essere 
class Base
{
public:
  virtual void fun() = 0;
};
In questo modo dichiari che la tua funzione NON ha implementazione.
Altrimenti ne devi fornire una (seppur minima), e il 
compilatore ne cerchera' una , dandoti errore se non la trova.
Quindi una seconda alternativa:
class Base_2
{
public:
  virtual void fun() {} ;
};
Qual'e' la differenza ?
Che nel secondo caso potresti castare alla classe base:
class der : public Base_2 
..
..
..
der* obj_der = new der ; 
obj_der->fun() ; // chiami fun di der.
((Base_2*)obj_der)->fun(); // chiami fun di Base_2 
Come vedi , in questo caso sei costretto a fornire un corpo alla funzione
fun() anche nella classe base. 
Non potresti fare la stessa cosa se la tua classe base e' Base , perche' 
dichiarando la funzione come 
 virtual void fun() = 0;
indichi al compilatore che fun() non ha implementazione, e come tale 
non puo' essere richiamata. 
Base non e' una vera e propria classe, ma un'Interfaccia, ovvero uno 
schema di funzioni che verranno implementate dalle classi derivate.
Salüti.
DB.

 };
Mi avevano indicato questa possibilita'.
Ma l'ho scartata perche' definendola poi in una successiva classe derivata
equivale ad un semplice overload e non a un metodo da implementare secondo
le direttive dell'interfaccia. In quel caso persino la parola chiave virtual
perde di significato.

 perde di significato.
ATTENZIONE!!!
Mi stai demolendo il polimorfismo !
La parola virtual non perde mai il suo significato. La seconda alternativa
e' *quasi* uguale alla prima, con l'unica differenza che la prima ti
costringe a definire il corpo della funzione, mentre la seconda ti 
fornisce comunque una implementazione di default. Qual'e' la migliore ?
La prima e' sicuramente la piu' elegante, ma in alcune situazioni 
la seconda e' piu' comoda ( tutta filosofia... per saperne di + 
leggi il Design Pattern ).
Per quanto riguarda la parola virtual : 
class base_1
{
public:
	void
	foo()
	{
		int a = 1 ; 
	};
};
class base_2
{
public:
	virtual void
	foo()
	{
		int a = 1 ; 
	};
};
class der_1 : public base_1
{
	void
	foo()
	{
		int a = 1 ; 
	};
} ;
class der_2 : public base_2
{
	void
	foo()
	{
		int a = 1 ; 
	};
} ;
//------------------------------------------------------------------------
void func_1( base_1& obj)
{
	obj.foo() ; 
} ;
void func_2( base_2& obj)
{
	obj.foo(); } ;
}
der_1 d_1 ; 
der_2 d_2 ; 
func_1(d_1) ; // verra' chiamata foo di base_1
func_2(d_2) ; // verra' chiamata foo di der_2
Come vedi, 2 comportamenti diversi per la sola parola virtual.
Provare in debug per credere.

 leggi il Design Pattern ).
Oh scusa se ho demolito qualcosa inavvertitamente :)
Cmq stavo facendo osservazioni basandomi sul modo di compilare del BCC 5.5.1
(peccato che ora non ho CygWin... avrei voluto provare volentieri)
E' passato un po' di tempo dall'ultima volta che ho studiato i costrutti C++
e ho una memoria skifosa... ma in teoria se ho una funzione virtuale in una
classe non dovrebbe essere impossibile creare un'istanza di quella stessa
classe? O valeva solo per le funzioni virtuali pure?

 
Sě.
Max