Newsgroup: it.comp.lang.c++
Titolo: problema con ereditarietà

Ho definito una classe Iv che eredita da Yx. Un oggetto Iv è un
vector<vector<double> >, con attributo di nome _iv.
Creo un oggetto di tipo Iv di nome iV. Se controllo le sue dimensioni
vedo che:
iV.size()=4.
size() è un metodo ereditato da Yx.
Adesso mando il messaggio iv() a iV.
iV1=iV.iv();
Mi aspetterei  che la dimensione  dell'attributo _iv  che vedo dentro
iv() sia anch'essa 4. Invece se dentro iv() faccio una chiamata:
_iv.size()
vedo che la dimensione di _iv è zero!! Questa volta chiaramente size()
è un metodo diverso, xché _iv è un vector<vector<double> >.
Aiuto, sono bloccato. Perché mi capita questo? Perché _iv non ha le
dimensioni aspettate? E' la 1a volta che uso l'ereditarietà. Non vedo
dove sia il problema..

 vector<vector<double> >, con attributo di nome _iv.
Un piccolo esempio compilabile che mostri il problema?
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg

Un piccolo esempio compilabile che mostri il problema?
Ecco :
/***************************************************************************/
#include <vector>
#include <iostream>
#define PRINT(A) cout << #A << " = " << A << endl;
using std::vector;
using std::ostream;
using std::cout;
using std::endl;
class Yx {
	private:
	vector<vector<double> > _xy;
	public:
	Yx() {}
	Yx(const vector<vector<double> > & v) { copy(v); }
	void copy(const vector<vector<double> > & v) {
		_xy.resize(0);
		vector<double> row;
		row.resize(0);
		for (unsigned i = 0; i < v.size(); i++) {
			for (unsigned j = 0; j < v[i].size(); j++)
				row.push_back(v[i][j]);
			_xy.push_back(row);
			row.resize(0);
		}
	}
	unsigned size() { return _xy.size(); }
};
class Iv: public Yx {
	private:
	vector<vector<double> > _iv;
	public:
	Iv() {}
	Iv(const vector<vector<double> > & v): Yx(v) {}
	void prova() { PRINT(_iv.size()); }
};
int main() {
	vector<vector<double> > v;
	vector<double> row;
	row.push_back(-50);
	row.push_back(-0.01);
	row.push_back(-0.03);
	row.push_back(-0.02);
	v.push_back(row);
	row.resize(0);
	row.push_back(-40);
	row.push_back(-0.1);
	row.push_back(0.1);
	row.push_back(-0.05);
	row.push_back(-0);
	v.push_back(row);
 
	Iv iv1(v);
	PRINT(iv1.size());
 
	iv1.prova();
}
/********************************************************************/
L'output che si ottiene è:
iv1.size() = 2
_iv.size() = 0
Quando mando il messaggio size() all'oggetto iv1, questo mi stampa
_iv.size(), cioè il n. di elementi dell'attributo. Dato che l'oggetto
iv1 ha 2 elementi, xché il suo attributo parrebbe avere 0 elementi?
Grazie1000

Esempio ancora più semplice:
/***********************************************************/
#include <iostream>
#define PRINT(A) cout << #A << " = " << A << endl;
using std::ostream;
using std::cout;
using std::endl;
class Yx {
	private:
	double _x;
	public:
	Yx() {}
	Yx(double x): _x(x) {}
	friend ostream & operator << (ostream & os, const Yx & yx) {
		os << yx._x;
		return os;	
	}
};
class Iv: public Yx {
	private:
	double _y;
	public:
	Iv() {}
	Iv(double y): Yx(y) {}
	void prova() { 
		PRINT(_y); 
	}
};
int main() {
	double v = 2.34;
	Iv iv1(v);
	cout << iv1 << endl;
 
	iv1.prova();
}
/**************************************************************************/
Da quello che capisco non posso accedere a member data di una classe
derivata, nemmeno dalla classe stessa! Come mai?

 	iv1.prova();
Qui finisci a scrivere Iv::_y, che non e` inizializzata.
Forse questo non e` l'esempio che avevi in mente.
-- 
   |   \    \  | ___|_  |_  | ianezz a casa sua... :-)
   |  _ \  | \ | _|    /   /  Visita il LinuxTrent a
  _|_/  _\_|  _|____|___|___| 
http://www.linuxtrent.it

 iv1 ha 2 elementi, xché il suo attributo parrebbe avere 0 elementi?
_xy nella classe base di iv1 ha due elementi.
Perche` _iv nella derivata dovrebbe contenerne qualcuno, se non viene 
manco inizializzato?


 Ecco :
Sostituisci
void prova() { PRINT(_iv.size()); }
con
void prova() { PRINT(size()); }
Il problema sta nel fatto che l'attributo _iv non viene mai toccato dal
tuo codice. Gli inserimenti interessano, infatti, solamente l'attributo
_xy della classe base.


Forse questo non e` l'esempio che avevi in mente.
credevo che _y venisse inizializzata automaticamente con _x. 
In casi come questi, in cui devo accedere agli attributi della classe
derivata, conviene definire "protected" gli attributi della classe
genitrice, piuttosto che "private", in modo da poter accedere a essi
dalla derivata senza dover fare due copie dei dati?

 dalla derivata senza dover fare due copie dei dati?
Mi sa che volevi scrivere "...in cui devo accedere agli attributi della 
classe BASE..." :-)
Nel qual caso andar di protected: e` una possibilita` offerta dal C++.
PERO`: se fai cosi`, il giorno che modifichi un pelo l'implementazione 
della classe base devi andare a toccare anche tutte le derivate che 
accedono direttamente agli attributi della classe base.
Se stai facendo una libreria di classi derivabili, tutte le volte che 
dichiari un attributo public: e protected: metti un'ipoteca sul futuro 
dell'implementazione interna, quindi meglio non andarci molto alla 
leggera (peraltro, l'ipoteca la metti anche quando dichiari public: o 
protected: un metodo).
Se ci pensi, protected e` poco meno di public, visto che non puoi 
impedire che ti derivino una classe aggiungendo metodi pubblici per 
accedere ad attributi o metodi protected.
Se la classe e` destinata prima o poi ad essere derivata, conviene 
riflettere a lungo su quale deve essere la sua interfaccia pubblica, ed 
usarla anche nelle classi derivate per accedere ai dati della classe base.
Dopodiche`, se dopo aver ponderato, l'interfaccia pubblica risulta ben 
fatta e quindi non sara` suscettibile di stravolgimenti, potrai 
modificare la sua implementazione senza dover necessariamente toccare 
anche il codice delle derivate (e senza sentire le bestemmie dei tuoi 
utenti sviluppatori che si lamentano che hai spostato una virgola nella 
tua classe e il loro codice che deriva da essa non funziona piu`).
Come ti avevan giustamente detto, l'errore logico e` di non usarla: hai 
gia` un metodo size() nella classe base, ereditato nella derivata, che 
ti ritorna la dimensione della collezione: basta usare quello anche 
nella derivata, invece che invocare size() direttamente su un attributo.
Dopodiche`, il C++ offre sempre chilometri di corda per impiccarsi con 
le modalita` che uno preferisce. :-)
