Probleme metode virtuale C++

Intrebari despre limbajul C++, standardul C++, STL, OOP in C++ sau alte subiecte nelegate de VisualC++
Euristica
Junior
Junior
Posts: 9
Joined: 08 Sep 2012, 23:38

Probleme metode virtuale C++

Post by Euristica » 22 May 2013, 04:20

Buna seara!

Revin pe forum dupa o lunga, dar oarecum constructiva absenta (de aproape un an). Intrucat am inceput studiul programarii orientate pe obiect, as avea cateva nelamuriri
1. Consultand diverse site-uri si materiale de specialitate, am inteles ca in cazul in care am o clasa de baza cu un membru de tip protejat, acesta poate fi accesat din clasele derivate printr-o mostenire publica. Insa in problema urmatoare, am o eroare la compilare in legatura cu virtual B D::f(B) tocmai din pricina faptului ca x este protejat si atunci nu poate fi accesat.
Iata programul:

Code: Select all

#include<iostream>
using namespace std;
class B
{ 
protected: int x;
public: B(int i=28) { x=i; } 
		virtual B f(B ob) { return x+ob.x+1; }
		void afisare(){ cout<<x; }
};
class D: public B
{ 
public: D(int i=-32):B(i) {}
		B f(B ob) { return x+ob.x-1; } 
};
		
int main()
{ 
	B *p1=new D, *p2=new B, *p3=new B(p1->f(*p2));
	p3->afisare();  
	return 0;
}
2. Din pacate, am probleme si cu functiile virtuale, mai ales la redefinirea lor in cazul utilizarii in clase derivate prin mostenire publica.
De exemplu, am lucrat la programul urmator (nu am pus si partea functia main(), deoarece nu aceasta ma "ingrijoreaza").

Problema suna in felul urmator:
Intr-o clinica vin mai multi donatori si primitori cu o anumita grupa de sange. Se da de la tastatura un vector de unitati de sange, cu o anumita grupa. In cazul in care grupa de sange a donatorului este aceeasi cu cea a uneidoze de sange, acea cantitate creste cu o unitate. Pentru primitor, daca grupa de sange este aceeasi cu cea a unei doze de sange, cantitatea respectiva scade cu o unitate(cu 1 ). M-am gandit sa pornesc cu acest enunt simplu si apoi sa complic problema, adaugand metoda compatibilitate si tinand seama si de cazul in care unitatile de sange din stoc nu au grupa necesara primitorului. Dar pana acolo am cateva erori de compilare la problema actuala.
Clase: Persoana din care deriva Donator si Primitor si care are o functie virtuala transfer
Doze_sange
Clinica care are obiecte de tip Doze_sange si Persoane si o metoda functionalitate prin care se face legatura intre obiecte.
In primul rand, la functia transfer din clasa Donator, nu-mi este recunoscut obiectul de tip Doze_sange *s. Tind sa cred ca nu am accesat corect campul grupasange din clasa Doze_sange. Aceeasi eroare imi apare si in cazul clasei Primitor.
Apoi, in clasa Clinica mi se spune ca transfer nu poate avea 2 parametri formali, lucru gresit, deoarece eu asa am declarat aceasta metoda in clasa Persoana

V-as ruga sa-mi oferiti macar un indiciu in legatura cu modalitatea de rezolvare a erorilor.

Va multumesc!

Code: Select all

#include<iostream>
#include<cstring>
using namespace std;
class Persoana  // clasa de baza 
{
protected:
	char nume[10], prenume[10], grupa_sange[4];
public:
	Persoana() {}
	Persoana(char *nume, char *prenume, char *grupa_sange); //constructor cu parametri
	virtual void transfer( Doze_sange *s, int n){}	  //metoda virtuala
	virtual ~Persoana(){ };  // destructor virtual
};

Persoana::Persoana(char *nume, char *prenume, char * grupa_sange) // definirea 

constructorului cu parametri din Persoana
{ 
	strcpy(this -> nume, nume); 
	strcpy(this -> prenume,prenume);
	strcpy(this -> grupa_sange,grupa_sange);
}

class Donator: public Persoana // clasa Donator derivata din Persoana
{	
public:	
	Donator() {}
	Donator(char *nume, char* prenume, char * grupa_sange):Persoana(nume,prenume,grupa_sange){} // apelul constructorului din cls de baza
	~Donator(){}	
	void transfer(Doze_sange *s, int n)	  
	{
		int result,i;
		for(i=0;i<n;i++)
		{
		result = strcmp(grupa_sange, s[i].grupasange);
		if(result== 0)
		{
			s[i].unitsg--;			
		}
	}	
}
};


class Primitor: public Persoana // clasa Primitor derivata din Persoana
{
public:	
	int n;
	Primitor() {}
	Primitor(char *nume, char* prenume, char* grupa_sange):Persoana(nume,prenume,grupa_sange){}
	~Primitor(){}
	void transfer(Doze_sange *x, int n)	  
		{
			int result,i;
			for(i = 0; i <n; i++)
			{
				result = strcmp(grupa_sange,x[i].grupasange);
				if(result == 0)
				{
					x[i].unitsg=x[i].unitsg-1;	
				}
			}	
		}
};


class Doze_sange
{
	int unitsg;
	char grupasange[4];
public:	
	Doze_sange(int _unitsg, char *grupasange)
	{
		unitsg=_unitsg;
		strcpy(this -> grupasange, grupasange);
	}
	Doze_sange(){}
	~Doze_sange() {}

};

class Clinica 
{
	int nr_doze, nr_donatori, nr_primitori;
public:
	Persoana *pv[10];
	Doze_sange *v[10]; 
	void citire(void)
	{
		int i; 
		char x[10], y[10], z[10], tip[10];
		cin >> nr_doze;
		cin >> nr_donatori;
		cin >> nr_primitori;
		int j;
		for( j = 0; j = nr_doze; j++)
		{ 
			cout<<"nr unit";cin>>nr_doze;
			cout<<"tip";cin>>tip;
			v[j] = new Doze_sange(nr_doze,tip);	}
		for (i=0; i < nr_donatori; i++)
		{
			cout << "Donatorii sunt:"<< endl;
			cout << "Donator"<<i<< endl;
			cout << "Nume donator" ; cin >> x;
			cout << "Prenume donator"; cin >> y;
			cout << "Grupa de sange"; cin >> z;
			pv[i] = new Donator(x,y,z);
		}
			
		for (i=nr_donatori; i <=nr_primitori; i++)	
		{
			cout << "Primitorii sunt:"<< endl;
			cout << "Primitor"<<i<< endl;
			cout << "Nume primitor" ; cin >> x;
			cout << "Prenume primitor"; cin >> y;
			cout << "Grupa de sange"; cin >> z;
			pv[i] = new Primitor(x,y,z);
		}
	}
	void functionare(void) // creste nr de unitati donatorul
	{ 
		int i;
		for(i=0; i<nr_donatori + nr_primitori; i++)
			pv[i] -> transfer(v,nr_doze);
	}
};
PS: Adineauri am citit intr-un post ca nu ar trebui sa folosesc char* pentru stringuri, ci std::string. Voi tine cont de acest lucru pe viitor, asadar sper sa nu fie o problema faptul ca acum am lasat codul in starea lui intiala!



User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Probleme metode virtuale C++

Post by Ovidiu Cucu » 22 May 2013, 08:53

1. Nu conteaza daca functia aia a ta este virtuala sau nu.

In principiu, pe scurt si (sper) pe inteles:
Poti accesa membrii protected din clasa de baza care sunt mosteniti/continuti in instanta curenta, nu si cei dintr-o instanta arbitrara a clasei de baza.
Adica daca ai

Code: Select all

class Base
{
protected:
   int m;
};
urmatorul cod este corect

Code: Select all

class Derived : public Base
{
public:
   int f1()
   {
      return this->m; // <-- OK.
   }
};
pe cand acesta iti va da eroare

Code: Select all

class Derived : public Base
{
public:
   int f2(Base b)
   {
      return b.m; // <-- cannot access protected member declared in class 'Base'
   }
};
Argumentul b al functiei Derived::f2 este o instanta oarecare a clasei Base.

Of course, cineva ar putea declara "friend class Derived" in clasa Base, insa atunci "strica" toata sfaraiala cu protected si private.

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Probleme metode virtuale C++

Post by Ovidiu Cucu » 22 May 2013, 09:41

2. Iarasi buba nu are legatura de functiile virtuale.

Daca ai

Code: Select all

class CFoo
{
   int m;
};
membrul CFoo::m este private si nu poate fi accesat in afara clasei CFoo.
Deci, ceva ca in exemplul urmator va da eroare

Code: Select all

class CBar
{
   int f(CFoo* p)
   {
      return p->m; // <-- cannot access private member declared in class 'CFoo'
   }
};

In exemplul tau, e vorba despre clasa Doze_sange cu membrii (implicit) privati Doze_sange::grupasange si Doze_sange::unitsg.
De ce sunt aia privati? Vezi care sunt deosebirile intre 'struct' si 'class'.
Iti recomand chiar sa-ti faci putin timp sa citesti si sa incerci sa intlegi toate "prostioarele" de acolo.

Mai sunt greseli insa sper ca deocamdata s-au lamurit macar astea doua.
Si-ar mai fi o mica observatie: iti faci viata mai complicata cu array-uri C-style (gen Doze_sange *v[10] si char grupasange[4]). Odata ce programezi in C++ si folosesti STL, ar fi bine sa incepi sa bagi mare cu std::vector si std::string.

Euristica
Junior
Junior
Posts: 9
Joined: 08 Sep 2012, 23:38

Re: Probleme metode virtuale C++

Post by Euristica » 22 May 2013, 13:02

Va multumesc pentru raspunsul prompt! Acum am inteles problema cu membrii protected dintr-o instanta a clasei de baza! Voi incepe sa citesc diseara ce mi-ati recomandat din sectiunea FAQ, Tips & Tricks
Intre timp, am corectat codul (greseala cea mai mare era ca eu foloseam membri ai clasei Doze_sange inainte sa definesc clasa) si in cele din urma imi compileaza programul, insa dupa apelul functiei citire, se opreste la apelul functiei "functionare", fix din cauza metodei transfer a clasei Persoana.
Intrebarea mea este urmatoarea:
- trebuie sa definesc un operator de adunare pentru clasa Doze_sange? Ma gandesc ca poate aici e problema..din pacate nu mi se da codul erorii, ci se opreste fix la linia cu

Code: Select all

pv[i]->transfer(*v,nr_doze);

Code: Select all

#include<iostream>
#include<cstring>
using namespace std;


class Doze_sange
{
public:

	int unitsg;
	char grupasange[4];

	Doze_sange(int _unitsg, char *grupasange)
	{
		unitsg=_unitsg;
		strcpy(this->grupasange, grupasange);
	}
	Doze_sange(){}
	~Doze_sange() {}

};

class Persoana  // clasa de baza 
{

protected:
	char nume[10], prenume[10], grupa_sange[4];
public:
	Persoana() {}
	Persoana(char *nume, char *prenume, char *grupa_sange); //constructor cu parametri
	virtual void transfer( Doze_sange *s, int n)/*intreg vectorul de unitati*/ {}	  //metoda virtuala
	virtual ~Persoana(){ };  // destructor virtual

};

Persoana::Persoana(char *nume, char *prenume, char * grupa_sange) // definirea constructorului cu parametri din Persoana
{ 
	strcpy(this -> nume, nume); 
	strcpy(this->prenume,prenume);
	strcpy(this->grupa_sange,grupa_sange);
}


class Donator: public Persoana // clasa Donator derivata din Persoana
{
	int n;
public:
	Donator() {}
	Donator(char *nume, char* prenume, char * grupa_sange):Persoana(nume,prenume,grupa_sange){} // apelul constructorului din cls de baza
	~Donator(){}	
	void transfer(Doze_sange *s, int n)	 
	{

		int result,i;
		for(i=0;i<n;i++)
		{
			//result = strcmp(grupa_sange,s[i].grupasange);
			//if(result==0)
			{
				s[i].unitsg--;			
			}
		}	
	}
};


class Primitor: public Persoana // clasa Primitor derivata din Persoana
{
public:
	int n;
	Primitor() {}
	Primitor(char *nume, char* prenume, char* grupa_sange):Persoana(nume,prenume,grupa_sange){}
	~Primitor(){}
	void transfer(Doze_sange *x, int n)	  
	{

		int result,i;
		for(i=0;i<n;i++)
		{
			result = strcmp(grupa_sange,x[i].grupasange);
			if(result==0)
			{
				x[i].unitsg=x[i].unitsg-1;			
			}
		}	
	}
};




class Clinica
{
	int nr_doze, nr_donatori, nr_primitori;
public:
	Persoana *pv[10];
	Doze_sange *v[10]; //initializez dinamic, ca la persoana

	void citire(void)
	{
		int i; char x[10],y[10],z[10],tip[10];
		cout<< "nr de doze:";cin >> nr_doze;
		cout << "nr de donatori"; cin >> nr_donatori;
		cout << "nr de primitori"; cin >> nr_primitori;
		int j;
		for( j = 0; j < nr_doze; j++)
		{ 
			cout<<"tip";cin>>tip;
			v[j] = new Doze_sange(nr_doze,tip);	
		}
		cout << "Donatorii sunt:"<< endl;
		for (i=0; i < nr_donatori; i++)
		{		
			cout << "Donator"<<i<< endl;
			cout << "Nume donator" ; cin >> x;
			cout << "Prenume donator"; cin >> y;
			cout << "Grupa de sange"; cin >> z;
			pv[i] = new Donator(x,y,z);
		}
		cout << "Primitorii sunt:"<< endl;

		for (i=nr_donatori; i <=nr_primitori; i++)	
		{			
			cout << "Primitor"<<i<< endl;
			cout << "Nume primitor" ; cin >> x;
			cout << "Prenume primitor"; cin >> y;
			cout << "Grupa de sange"; cin >> z;
			pv[i] = new Primitor(x,y,z);
		}

	}

	void functionare(void) 

	{ 
		int i;
		for(i=0;i<nr_donatori+nr_primitori;i++)
			pv[i]->transfer(*v,nr_doze);

	}

};



int main()
{
	Donator a;
	Clinica c;
	c.citire();
	c.functionare();
}

Ei, am incercat sa pun in aplicare partea cu std::vector si std::string, dar mi-am cam prins urechile. Insa voi mai citi despre acest lucru si voi reveni cu clasele scrise in acel mod.

Euristica
Junior
Junior
Posts: 9
Joined: 08 Sep 2012, 23:38

Re: Probleme metode virtuale C++

Post by Euristica » 23 May 2013, 02:50

Am revenit cu un cod schimbat, deoarece mi-am dat seama ca de fapt, la final nu afisam nimic concret.Problema este ca s-a mentinut eroarea la debug: "Unhandled exception at 0x002a1d93 in poomancu.exe: 0xC0000005: Access violation reading location 0xcccccccc." Practic, nu se apeleaza functia transfer asa cum trebuie. Doar ca sincer, nu inteleg de ce...

Code: Select all

#include<iostream>
#include<cstring>
using namespace std;


class Doze_sange
{
public:

	int unitsg;
	char grupasange[4];

	Doze_sange(int _unitsg, char *grupasange)
	{
		unitsg=_unitsg;//trebuie sa initializez doar o unitate de sange, nu un vector
		strcpy(this->grupasange, grupasange);
	}
	Doze_sange(){}
	~Doze_sange() {}

};

class Persoana  // clasa de baza 
{

protected:
	char nume[10], prenume[10], grupa_sange[4];
public:
	Persoana() {}
	Persoana(char *nume, char *prenume, char *grupa_sange); //constructor cu parametri
	virtual int transfer( Doze_sange *s, int n)=0;/*intreg vectorul de unitati*/	  //metoda virtuala
	virtual ~Persoana(){ };  // destructor virtual

};

Persoana::Persoana(char *nume, char *prenume, char * grupa_sange) // definirea constructorului cu parametri din Persoana
{ 
	strcpy(this -> nume, nume); 
	strcpy(this->prenume,prenume);
	strcpy(this->grupa_sange,grupa_sange);
}


class Donator: public Persoana // clasa Donator derivata din Persoana
{
	int n;
public:
	Donator() {}
	Donator(char *nume, char* prenume, char * grupa_sange):Persoana(nume,prenume,grupa_sange){} // apelul constructorului din cls de baza
	~Donator(){}	
	int transfer(Doze_sange *s, int n)	  // ce ar putea sa faca? 
	{

		int result,i;
		for(i=0;i<n;i++)
		{
			result = strcmp(grupa_sange,s[i].grupasange);
			if(result==0)
			{
				s[i].unitsg=s[i].unitsg+1;			
			}
			return s[i].unitsg;
		}	
	}
};


class Primitor: public Persoana // clasa Primitor derivata din Persoana
{
public:
	int n;
	Primitor() {}
	Primitor(char *nume, char* prenume, char* grupa_sange):Persoana(nume,prenume,grupa_sange){}
	~Primitor(){}
	int transfer(Doze_sange *x, int n)	  // ce ar putea sa faca? 
	{

		int result,i;
		for(i=0;i<n;i++)
		{
			result = strcmp(grupa_sange,x[i].grupasange);
			if(result==0)
			{
				x[i].unitsg=x[i].unitsg-1;			
			}
			return x[i].unitsg;
		}	
	}
};




class Clinica // ce face aceasta clasa? cum se face dubla legare intre clase? 
{
	
public:
	int nr_doze, nr_donatori, nr_primitori;
	Persoana *pv[10];
	Doze_sange *v[10]; //initializez dinamic, ca la persoana

	void citire(void)
	{
		int i; char x[10],y[10],z[10],tip[10];
		
		cout << "nr de donatori"; cin >> nr_donatori;
		cout << "nr de primitori"; cin >> nr_primitori;
		int j;
		for( j = 0; j < nr_donatori+nr_primitori; j++)
		{ 
				cout<< "nr de doze:";cin >> nr_doze;
			cout<<"tip";cin>>tip;
		
			v[j] = new Doze_sange(nr_doze,tip);	
		}
		cout << "Donatorii sunt:"<< endl;
		for (i=0; i < nr_donatori; i++)
		{		
			cout << "Donator"<<i<< endl;
			cout << "Nume donator" ; cin >> x;
			cout << "Prenume donator"; cin >> y;
			cout << "Grupa de sange"; cin >> z;
			pv[i] = new Donator(x,y,z);
		}
		cout << "Primitorii sunt:"<< endl;

		for (i=nr_donatori; i <=nr_primitori; i++)	
		{			
			cout << "Primitor"<<i<< endl;
			cout << "Nume primitor" ; cin >> x;
			cout << "Prenume primitor"; cin >> y;
			cout << "Grupa de sange"; cin >> z;
			pv[i] = new Primitor(x,y,z);
		}

	}

	void functionare(void) // creste nr de unitati donatorul
	{ 
		int i,total[100];
		for(i=0;i<nr_donatori+nr_primitori;i++)
			{

				total[i]+=pv[i]->transfer(*v,nr_doze);	
		}
		for(i=0;i<=nr_donatori+nr_primitori;i++)
				{cout<<"au ramas "<<total[i] <<"Unitati de sange de tip";
		}}

};



int main()
{
	
	Clinica c;
	c.citire();
	c.functionare();
}

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Probleme metode virtuale C++

Post by Ovidiu Cucu » 23 May 2013, 10:38

Euristica wrote:greseala cea mai mare era ca eu foloseam membri ai clasei Doze_sange inainte sa definesc clasa
Nu asta era greseala cea mai mare. Da, era o greseala insa cel mai usor de detectat/corectat printre toate celelalte.
Ca sa eviti asemenea greseli, nu mai pune tot codul buluc intr-un singur fisier. Pune frumusel definitia fiecarei clase in headerul ei, iar implementarea fiecarei clase in cate un CPP.
Euristica wrote:trebuie sa definesc un operator de adunare pentru clasa Doze_sange?
NU. Sau mai binezis, vorba englezului "you can but you may not". Ce facem daca adunam o doza grupa 0 cu una grupa AB? Aruncam o exceptie din operator? Nu, asa ceva nu se face, poate doar un architect tembel sa faca... :)
Euristica wrote:Ei, am incercat sa pun in aplicare partea cu std::vector si std::string, dar mi-am cam prins urechile.
Pun pariu ca daca incerci sa deslusesti "tainele" lui std::cin si std::cout (dincolo de a folosi doar chestii de genu cin >> n) iti prinzi urechile mai repede.
Euristica wrote: "Unhandled exception at 0x002a1d93 in poomancu.exe: 0xC0000005: Access violation reading location 0xcccccccc."
Asta-i pentru ca te joci cu acele array-uri C-style de care-ti spuneam. Trebuie sa fii atent sa nu dai pe din laturi, peste vreun element care-i in balarii s.a.m.d.
std::vector si std::string te scuteste de asemenea dureri de cap.

Mai in gluma, mai in serios:
Banui ca scopul programului este evidenta stocului de sange precum si a pacientilor (donatori si primitori), sa zicem, intr-un spital.
Daca un profesor ti-a sugerat "design-ul" de mai sus, spune-i te rog ca-i urez multa sanatate si sa n-ajunga vreodata sa faca transfuzie intr-o clinica ce foloseste un asemenea program. :)

O sa incerc in continuare sa-ti schitez ceva care i-ar putea da mai multe sanse de supravietuire. ;)
Voi folosi std::vector si std::string, pe de o parte pentru ca nu vreau sa pierd timpul scriind cod C, pe de alta parte ca sa-ti arat ca std::vector si std::string nu-s chiar de prins urechile.

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Probleme metode virtuale C++

Post by Ovidiu Cucu » 23 May 2013, 13:46

Sa incepem cu donatorii si primitorii.
Din start, modelul class Persoana din care deriva class Donator si class Primitor nu-i OK. Pe o perioada mai lunga te timp, aceeasi persoana poate fi atat donator cat si primitor aparand redundant in doua locuri. Nu facem derivare de dragul derivarii. Asa ceva face doar un architect care n-a auzit de KISS si pe care orcum il doare-n cot, pentru ca-i platit la numarul de clase si la cati pereti umple el cu diagrame... :)
Avem nevoie de o singura clasa care imi tine un pacient, sa-i zicem CPatient.
Cam asa:

Code: Select all

// Patient.h - CPatient class definition
#pragma once
#include "BloodType.h"
#include <string>

class CPatient
{
// Attributes
private:
   std::string m_sFirstName; // prenume
   std::string m_sLastName;  // nume
   std::string m_sID;        // identificator unic (CNP)
   CBloodType m_bloodType;   // grupa sanguina + rh

// Constructors/destructor
public:
   CPatient();
   ~CPatient();

// Operations
public:
   void SetFirstName(const std::string& sValue);
   void SetLastName(const std::string& sValue);
   void SetID(const std::string& sValue);
   void SetBloodType(const CBloodType& blood);

   const std::string& GetFirstName() const;
   const std::string& GetLastName() const;
   const std::string& GetID() const;
   const CBloodType& GetBloodType() const;
};

#include "Patient.inl"
Deci, avem o structura de date (clasa) care contine numele si prenumele unui pacient (donator sau primitor, nu conteaza), un identificator unic (sa zicem CNP) si grupa sanguina, plus meodele Set/Get corespunzatoare.
De ce am introdus identificatorul unic?
Simplu, pentru a scade numarul de decese provocat de confuziile privind pacienti cu acelasi nume si prenume insa cu grupe sanguine diferite. :)
De ce am folosit o clasa CBloodType si nu pur si simplu un string care sa tina ceva gen "0-", "AB+", etc?
Simplu, pentru a nu scrie mai tarziu o tona de cod intr-o functie care sa stabileasca compatibilitatie, sau in functii care sa verifice daca tanti de la urgente nu baga mascari de la tastatura. Astfel, contibuim de asemenea la scaderea deceselor. Voi arata si aceasta clasa in episodul urmator.

E clar pana aici? Daca nu, te rog sa intrebi.
De asemenea, daca e vreun medic pe receptie, il rog sa sara-n sus daca scriu ceva gresit! :D

[va urma]

viorel2005
Membru
Membru
Posts: 208
Joined: 24 May 2008, 09:41

Re: Probleme metode virtuale C++

Post by viorel2005 » 23 May 2013, 17:03

Chiar daca e scris in C#, cel mai bine e sa gandesti aplicatia in acesti termeni:
http://www.codeproject.com/Articles/572 ... tterns-and

Solutia pusa pe forum nu se preteaza la o aplicatie reala de C++, decat daca este client/server cu o baza de date.
Din pacate, aplicatiile in ziua de azi sunt mai complexe. Si cum multi se plang ca Java e complicat, deoarece
te face sa lucrezi in maniera POO adevarata, asa ca sfatul meu este sa urmaresti articolul de mai sus si sa incerci
sa vii cu o solutie ca acea publicata pe codeproject. Asa codul tau va fii mai bun.
Si pentru cei care spun ca lucrurile simple sunt eficiente, citeste acest articol:

http://www.codeproject.com/Articles/195 ... eys-A-Wolf

Ai sa vezi ca si in lumea .NET putin "asm .net" nu strica.

Legat de metode virtuale, incearca sa studiezi Visitor pattern.Un exemplu il ai aici:
http://login2win.blogspot.ro/2011/06/vi ... ttern.html

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Probleme metode virtuale C++

Post by Ovidiu Cucu » 23 May 2013, 17:42

@viorel2005
Oooop!!!
Hai sa-ti vedem solutia (concret cu cod) ca de link-uri si titluri din GoF ne-am saturat!
Dupa aceea discutam, comparam si vedem care-i mai buna si/sau mai aproape si pe intelesul OP.

viorel2005
Membru
Membru
Posts: 208
Joined: 24 May 2008, 09:41

Re: Probleme metode virtuale C++

Post by viorel2005 » 23 May 2013, 21:14

Clasa CPersoana are dezavantajul ca nu are proprietati dinamice.
Intrebarea care se pune: care sunt proprietatile dinamice si care sunt proprietatile statice.
Sa luam de exemplu grupa de sange. Daca o persoana face un tratament antileucemie si
are un transplant de maduva, ADN-ul se schimba. Deci nu putem spune ca va avea
aceeasi grupa de sange din punct de vedere al probelor. Are un ADN in firele de par vechi, dar in saliva are alt ADN.
Daca acest lucru se afla pe parcurs si se mai cer alte campuri, o solutie e sa gandesti dinamic clasa de la inceput
conform urmatorului hack C++:http://www.michael-hammer.at/blog/c++_d ... trization/.
La clasa existrenta, intrebarea este: care sunt proprietatile statice si care sunt cele dinamice?

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Probleme metode virtuale C++

Post by Ovidiu Cucu » 24 May 2013, 07:43

Humble me, incerc sa-i demonstrez omului ca std::string nu-i chiar de speriat iar tu ii tantesti un exemplu (link of course) care foloseste boost::any.
Cool! :)

Euristica
Junior
Junior
Posts: 9
Joined: 08 Sep 2012, 23:38

Re: Probleme metode virtuale C++

Post by Euristica » 24 May 2013, 20:06

Ei, ce-i drept, clasa prezentata de dl Cucu este cu adevarat pe intelesul meu, cu atat mai mult cu cat aduce mai mult cu programul ce ar putea fi utilizat intr-o clinica reala. Din pacate, inca sunt o ucenica intr-ale programarii orientate pe obiect si inca mai am probleme cu intelegerea unor notiuni fundamentale, asa ca linkurile date de viorel2005 imi vor fi de folos, dar mai tarziu..nu as vrea sa ard etape in acumularea de informatii pentru ca fiecare concept este important!

viorel2005
Membru
Membru
Posts: 208
Joined: 24 May 2008, 09:41

Re: Probleme metode virtuale C++

Post by viorel2005 » 25 May 2013, 17:14

Aveti dreptate in privinta complexitatii. Dar tinand cont de experienta celor de pe forum, o discutie constructiva nu ar strica.
Nu cer o solutie GOF direct. Dar o discutie privind arhitectua aceste aplicatii ar fii utila.
De exemplu:
-crearea unui namespace special care sa contina:
- o clasa abastracta Object.
- o clasa IPersoana derivata din Object
-o clasa Persoana
-o clasa Persoane derivata din std::vector<IPersoana>
sau std::map
etc.

Problemele sunt urmatoare:
1) ce tipuri de obiecte sunt necesare pentru multi-thread
2) ce tipuri de obiecte sunt necesare pentru comunicarea in retea
3) ce tipuri de obiecte sunt necesare pentru comunicarea cu baze de date

Clasa Object are utilitatea pentru conversii, transport si de a stii ce obiect am la un moment dat.
Intrebarea care se pune este urmatoarea: ce proprietati/metode ar trebuie adaugate
pentru a rezolva probleme 1),2) si 3). Ideea este de a avea niste proprietati
utile asfelt incat sa iti usereze munca cu alte librarii C++.
De exemplu, pentru baze de date mi-ar placea sa am o facilitate asemenea databiding din .net.
Intrebarea este: merita acest lucru in C++? In legatura cu clasa Persoana prezentata de Ovidiu,
intrebarea este: ce functii mai adaugam astfel utilizatorul clasei sa nu o foloseasca neadecvat?
De exemplu: nu stiu daca a fost creata cu scopul de a putea scrie:

Code: Select all

Persoana P1,P2;
...//cod
P2=P1;//e corect in forma actuala a clasei?
Apreciez munca lui Ovidiu si a celorlalti colegi pentru timpul acordat pe forum pentru a rezolva
diverse probleme sau a da indicatii. Dar cred ca extinderea acestei probleme in sensul de discutie de
desing a arhitecturii aplicatiei si apoi de implementare ar fii de real ajutor pentru cei care citesc postarile
publicate pe acest forum. Faptul ca cineva are experienta in C++ si scrie cod nu inseamna ca
el nu poate isi imbunatatii aptitudinile prin comunicare. Partea de design nu se discuta pe
forumuri in general. Mai mult erorile aparute. De aceea am continuat acest post.
Pentru a vedea o discutie si o realizare in afara framework-urilor. Nu inseamana ca
daca stii cartea GoF, solutiile vor fii la fel. Nu pot sa scriu un cod cum e in GoF.
Dar pot sa pun intrebari de genul: de ce asa si nu asa., pentru ca eu am citit urmatorul lucru.
Si poate sunt multi care au alta idei de design si stiu sa scrie si cod vor aduce alte argumente.
Arhitectura iti poate penaliza sau nu performanta. Robustetea costa de obicei.
A nu lasa utilizatorul sa greseasca, uneori complica situatia nu o simplifica.
C++ iti permite sa mergi in ambele directii. Alte limbaje nu.

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Probleme metode virtuale C++

Post by Ovidiu Cucu » 25 May 2013, 17:47

Nicolaus Copernicus, plasand in centru Soarele in locul Pamantului, n-a facut altceva decat sa aplice KISS paradigm. Era mai simplu de explicat haosul miscarii astrelor pe cer. Dar deh, a incalcat niste dogme invatate de altii pe de rost.
Astazi acele dogme se numesc in programare "Design Patterns", initial scrise cu cele mai bune intentii pentru a elimina haosul in implementare, insa care din pacate au dus la haos in design datorita celor care le invata pe de rost.

Continuam cu KISS? Poate ajungem din nou on-topic si sa vorbim despre "Probleme metode virtuale C++".

viorel2005
Membru
Membru
Posts: 208
Joined: 24 May 2008, 09:41

Re: Probleme metode virtuale C++

Post by viorel2005 » 25 May 2013, 19:30

Atunci o sa incep eu.
Clasa lui Ovidiu are urmatoarea problema. Notificarile. Acest lucru se face cu pattern-ul Observer.
Un exemplu de implementare este aici:
Ideea este ca pacientul este monitorizat si in functie de acestea se trimit notificarile in sistem. Sa presupunem
ca, in urma analizelor, s-a descoperit ca rezervele de sange pentru grupa A, Rh pozitiv sunt suficiente.
Drept urmare ar trebui sa fie oprita acceptarea de donatori cu aceasta grupa de sange. Drept urmare
acest pattern ajuta. Problema este in practica , cuplarea pattern-urilor.
Dar inainte de asta, se pune intrebarea: Este nevoie de acest pattern intr-o aplicatie medicala?
Aplicatiile medicale sunt pretentioase, deoarece nu trebuie sa contina erori. Deci principiul KISS se impune.
SI Autocad ofera service-pack-uri si e folosit in proiectare, dar pentru o aplicatie medicala este important
sa fie cat mai robusta.

Post Reply