Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
Trinitas TV 4K

Dacia 1316 cu 6 usi ...

Frecventa modificata radio

Un nou pericol pt batrani
 Ar trebuii sa vindem imobiliarele...

Dupa renuntarea la aparat dentar

pelerinaj in Balcik

Noul format Jpegli iși propu...
 Dade, dade

Probleme accesare nr test telefon

Parola la lock screen

Deparazitare externa pisici fara ...
 Seriale turcesti/coreene online H...

Merita un Termostat Smart pentru ...

Sfat achizitie MTB Devron Riddle

Problema mare cu parintii= nervi ...
 

De la C la C++

- - - - -
  • Please log in to reply
44 replies to this topic

#19
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,238
  • Înscris: 24.02.2007

View PostTS030, on 12 iulie 2013 - 21:53, said:

Observ ca mentionezi programarea orientata obiect, dar nu povestesti despre ea si nu exemplifici Posted Image

Ideea a fost de a le starni curiozitatea celor care n-au auzit inca de POO, sa inceapa sa citeasca despre ea, iar, pe masura ce vad cum stau lucrurile, de a exersa cu ajutorul unor studii de caz. Adica ei sa vina cu o problema concreta, intalnita de ei si cu solutia POO la care s-au gandit, iar noi sa o imbunatatim.

N-a prea mers insa (inca) ideea, fiindca, in afara de ce am prezentat eu mai sus, nu s-a aratat nimeni interesat.

View PostTS030, on 12 iulie 2013 - 21:53, said:

De asemenea, incerci sa vorbesti despre prea multe lucruri deodata, iar structura are de suferit.

Am observat si eu ca, in acest caz, am obtinut o structura destul de haotica. Sper s-o rafinez pe parcurs.

#20
TS030

TS030

    Guru Member

  • Grup: Senior Members
  • Posts: 15,193
  • Înscris: 25.06.2012
Sincer mi se pare ca subiectul abordat abia ar putea fi prins intr-o carte... din fericire, aceasta a fost scrisa deja.

Referitor la OOP, problema e ca nici n-ai inceput sa atingi subiectul, ceea ce poate pacali un incepator.
"Componente care rezolva o anumita problema" pot fi si proceduri sau module; desigur, programarea procedurala nu este programare orientata obiect. Nici daca acele componente sunt clase C++ nu poti spune ca programezi neaparat orientat obiect. Exemplul cu HTTPDownloader, ExchangeRateParser, FileWriter care fiecare-si face treaba nu spune nimic despre OOP.
Pana nu vorbim de ierarhii de clase, nu vorbim despre OOP.

#21
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,238
  • Înscris: 24.02.2007
Am mentionat si ierarhii de clase, exemplul cu Persoana/Elev.

#22
adrian93

adrian93

    Active Member

  • Grup: Members
  • Posts: 1,740
  • Înscris: 29.10.2009
Fix în perioada aceasta m-am apucat de tranziția propriu-zisă, de la C la C++ (mai specific, POO), așa că am încercat să rezolv ”Tema” propusă de dani.user.

String.h
#pragma once
#include <cstring>
namespace Mylib
{
  class String
  {
	char* text;
  public:
	String();
	String(const char* data);
	int length();
	char* subString(int i);
	//String subString(int i);
	char* toCharPointer();
	String& operator=(const char* data);
	String& operator=(String& strdata);
	String operator+(String& strdata);
	char operator[](int i);
	String& operator+=(const char* data);
	String& operator+=(String& strdata);
	~String();
  };
}


String.cpp
#include <cstring>
#include "String.h"
using namespace Mylib;
String::String()
{
  text = new char[1];
  text[0] = '\0';
}
String::String(const char* data)
{
  text = new char[strlen(data) + 1];
  strcpy(text,data);
}
int String::length()
{
  return strlen(text);
}
char* String::subString(int i)
{
  if (i >= 0 && this->length() >= i)
	return text + i;
}
/*String String::subString(int i)
{
  if (i >= 0 && this->length() >= i)
  {
	char* buffer = new char[strlen(text+i) + 1];
	strcpy(buffer,text+i);
	String ret(buffer);
	delete[]buffer;
	return ret;
  }
}*/
char* String::toCharPointer()
{
  return text;
}
String& String::operator=(const char* data)
{
  delete[]text;
  text = new char[strlen(data) + 1];
  strcpy(text,data);
  return *this;
}
String& String::operator=(String& strdata)
{
  if (this != &strdata)
  {
	delete[]text;
	text = new char[strlen(strdata.text) + 1];
	strcpy(text,strdata.text);
	return *this;
  }
}
String String::operator+(String& strdata)
{
  int size = strlen(text) + strdata.length() + 1;
  char* buffer = new char[size];
  buffer = strcpy(buffer,text);
  buffer = strcat(buffer,strdata.text);
  String ret(buffer);
  delete[]buffer;
  return ret;
}
char String::operator[](int i)
{
  if (i >= 0 && this->length() >= i);
	return text[i];
}
String& String::operator+=(const char* data)
{
  int size = strlen(text) + strlen(data) + 1;
  char* buffer = new char[strlen(text) + 1];
  buffer = strcpy(buffer,text);
  delete[]text;
  text = new char[size];
  text = strcpy(text,buffer);
  delete[]buffer;
  text = strcat(text,data);
  return *this;
}
String& String::operator+=(String& strdata)
{
  int size = strlen(text) + strlen(strdata.text) + 1;
  char* buffer = new char[strlen(text) + 1];
  buffer = strcpy(buffer,text);
  delete[]text;
  text = new char[size];
  text = strcpy(text,buffer);
  delete[]buffer;
  text = strcat(text,strdata.text);
  return *this;
}
String::~String()
{
	delete[] text;
}


test.cpp
#include <stdio.h>
#include "String.h"
using namespace Mylib;
int main()
{
  String a;
  a = "Hello ";
  int sizeA = a.length();
  String b("World");
  String c = a + b; //Hello World
  c += " din C++";
  c += a;
  String d = c.subString(3); //lo World din C++Hello
  printf("%s\n",d.toCharPointer());
  printf("%c",c[0]); // H
  return 0;
}


Pentru că sunt încă pe la început de tot și pentru că doresc să învăț, aș aprecia dacă mi-ați oferi feedback și observații: unde mai e de lucrat, ce deprinderi greșite se observă, ce nu e deloc bine ș.a.

Aș avea câteva întrebări cu privire la supraîncărcarea operatorilor:
1. De ce se practică transmiterea argumentelor prin const &? const pare cam de amorul artei, dar de ce este necesară adresa obiectului, având în vedere că și în cazul în care operatorul supraîncărcat este cel de atribuire, în cazul a = b, nu ne interesează b decât la nivel de valoare, deci putem opera cu o copie de-a lui b.
2. De ce este nevoie ca atunci când supraîncărcăm ”=”, rezultatul funcției să fie o referință?
String& String::operator=(const char* data)
{
  ...
  return *this;
}


O altă chestie pe care am observat-o este că funcțiile ce întorc o referință la un obiect prezintă în instr. return obiectul/ valoarea. Mi se pare normal ca în cazul a = b, rezultatul să fie un String, ca atare întorc *this, adică un obiect. Cu toate astea, funcția are ca rezultat String&. Cum de nu există un conflict între tipul funcției și tipul returnat?

De asemenea, am întâmpinat ceva probleme când am încercat să implementez funcția subString astfel încât să returneze un obiect de tip String (liniile de cod comentate).
Dacă înlocuim funcția char* subString cu cea String subString, o să apară memory map-ul, se pare că problema ar fi un double free/ corruption. Am încercat să fac debug cu gdb-ul, însă nu m-am prins de la ce ar putea fi problema: se pare că ar crăpa cam pe la finalul execuției, când s-ar apela destructorul.

#23
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,238
  • Înscris: 24.02.2007
  • & indica faptul ca parametrul este trimis prin referinta. Astfel se evita crearea unui copii a lui care poate fi destul de costisitoare. E o varianta mai comoda si mai sigura decat transmiterea unui pointer fiindca in cazul lui poti trimite si null sau pointer la balarii. const te asigura pe tine, care apelezi functia, ca aceasta nu va modifica parametrul, astfel incat poti dormi linistit chiar daca il transmiti prin referinta.

  • String a = "qwerty";
    a = "1234";
    
    

    Daca n-ai returna referinta ai crea o copie inutila. Deasemena iti permite ceva de genul
    (a = "1234") += "5678";
    
    

    Referintele au aparut pentru a mai "scapa" de atatea * folosite in cazul pointerilor. Daca tu ai declarat functia ca returnand o referinta, compilatorul stie ca asta vrei chiar daca instructiunea return arata la fel ca in cazul neutilizarii referintei.

  • Daca dai de probleme neexplicate legate de memorie, deseori au drept cauza faptul ca ai omis sa definesti constructorul de copiere
    String::String(const String& string);
    
    

    Cand acesta e omis, compilatorul creaza automat unul, insa acesta nu va sa copieze datele spre care tinteste text, ci va copia doar adresa ca o simpla valoare numerica.

    Urmatorul cod arata ce constructor e apelat cand
    String a("1234"); //String::String(const char*)
    String b = "1234"; //String::String(const char*)
    b = "5678"; //String::operator=(const char*)
    String c(b); //String::String(const String&)
    String d = b; //String::String(const String&)
    d = a; //String::operator=(const String&)
    
    

    In implemetarea ta subString chiar asta se si intampla:
    return ret;
    
    

    Deoarece returnezi String nu String&, aici e apelat constructorul de copiere generat automat ce doar copiaza adresa lui text, ret e distrus apoi fiindca iese din scope si sterge ce se afla la adresa indicata de text, iar String-ul returnat ramane cu text in aer.


  • Codul celor doua variante operator+= e aproape identic, se repeta.
    String& String::operator+=(String& strdata)
    {
       return *this += stddata.text;
    }
    
    

  • Implementarea length() itereaza caracter cu caracter de fiecare data cand e apelata. Ai putea s-o optimizezi calculand lungimea doar cand stii ca se schimba


#24
adrian93

adrian93

    Active Member

  • Grup: Members
  • Posts: 1,740
  • Înscris: 29.10.2009
Mulțumesc pentru feedback și pentru explicații.

1. Să văd dacă am înțeles bine: am considerat o funcție care să simuleze cam ceea ce se petrece acolo când supraîncărcăm operatorul de atribuire.
#include <cstdio>
// int test(int &a)
int& test(int &a)
{
  return a;
}
int main()
{
  int a = 5;
  test(a) = 4;
  printf("%d",a);
  return 0;
}


În cazul prototipului comentat (int test()), transmitem o variabilă prin referință, și o returnăm un int, deci o valoare. Ceea ce înseamnă ca test(a) = 4 ar fi 5 = 4, ceea ce nu are sens (compilatorul a dat eroare).
În cazul prototipului (int& test()), returnăm o adresă, dar nu dpdv al valorii numerice (0x1A....), ci practic o variabila ”a” în sine? test(a) = 4 observ că va merge.

3. Aha, nu știam că este necesar și un constructor pentru copiere. Voi încerca să implementez unul să văd dacă mai sunt probleme.
4. Nu ar fi redundantă și supraîncărcarea op. += (implementarea funcției)? Dacă supraîncărcăm op. +, precum și op. =, atunci prin a += b, nu ar trebui ca compilatorul să accepte faptul că s-ar petrece a = a + b, pentru că putem folosi deja + și = în astfel de expresii? Am putea în felul acesta să facem un fel de ”compuneri” între operatori? Dar văd că nu prea merge...
5. Hm, păi atunci ar merge să adăugăm în cadrul clasei o variabilă size, care se modifică numai când este apelat constructorul/ + / = / alte operații, iar funcția length() să îi returneze valoarea?

#25
alexuts56

alexuts56

    Junior Member

  • Grup: Members
  • Posts: 175
  • Înscris: 27.12.2010
Am rezolvat si eu tema. Daca ai putea arunca o privire si pe la mine ti-as fi recunoscator.
Am facut si o functie care imi afisa sirurile, sa fiu sigur ca functioneaza. Inca n-am inteles cum s-a facut in pagina anterioara, cu cout sa se afiseze membrii clasei polinom. O sa ma mai uit. Posted Image
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
namespace MyLib
{
class String
{
private:
char *sir;
public:
String(){ }
String(const char *sir);
~String();
void operator=(const char *sir);
void operator=(String string2);
char operator[](int nr);
String operator+(String string2);
void operator+=(const char *sir);
int length();
String subString(int numar);
char *toCharPointer();
void print();
};
} // namespace
using namespace MyLib;
String::~String()
{
delete [] sir;
}
void String::print()
{
cout << sir << endl;
}
String::String(const char *sir)
{
this->sir = new char [strlen(sir)+1];
strcpy(this->sir, sir);
}
void String::operator=(const char *sir)
{
this->sir = new char [strlen(sir)+1];
strcpy(this->sir, sir);
}
void String::operator=(String string2)
{
this->sir = new char [strlen(string2.sir)+1];
strcpy(this->sir, string2.sir);
}
void String::operator+=(const char *sir)
{
String auxiliar;
auxiliar.sir = new char [strlen(this->sir)+1];
strcpy(auxiliar.sir, this->sir);
delete [] this->sir;
this->sir = new char [strlen(auxiliar.sir)+strlen(sir)+1];
strcpy(this->sir, auxiliar.sir);
strcat(this->sir, sir);
}
int String::length()
{
return (strlen(sir));
}
char String::operator[](int nr)
{
return (this->sir[nr]);
}
String String::operator+(String string2)
{
String auxiliar;
auxiliar.sir = new char [strlen(this->sir)+strlen(string2.sir)+1];
strcpy(auxiliar.sir, this->sir);
strcat(auxiliar.sir, string2.sir);
return auxiliar;
}
char* String::toCharPointer()
{
return (this->sir);
}
String String::subString(int numar)
{
String *aux = new String ;
aux->sir = this->sir+numar;
return *aux;
}

int main()
{
String a;
a = "Hello ";
a.print();
int sizeA = a.length();
cout << sizeA << endl;
char litera = a[1];
cout << litera << endl;
String b("World");
b.print();
String c;
c = a+b;
c.print();
c += " din C++";
printf("%s \n", c.toCharPointer());
String d = c.subString(3);
d.print();
return 0;
}


Edited by alexuts56, 15 July 2013 - 07:54.


#26
Cy_Cristian

Cy_Cristian

    Active Member

  • Grup: Members
  • Posts: 1,845
  • Înscris: 22.02.2009
@adrian93. Ai o mica problema la cod. Norocul tau este ca aceeasi problema a existat si la CString in versiunile initiale. Deci esti intr-o companie selecta Posted Image.
@alexuts56.
Supraincarcarea operatorului de atribuire nu se face cum ai facut tu:
void operator=(String string2);
ci
String& operator=(const String& string2);
Motivele au fost expuse in alte postari anterioare.
operatorul[] trebuie neaparat sa arunce exceptie.
metoda length nu trebuie sa calculeze de fiecare data lungimea. S-a amintit deja.

String String::subString(int numar)
{
String *aux = new String ;
aux->sir = this->sir+numar;
return *aux;
}


Aici ai probleme mari, cea mai mare fiind un memory leak de toata frumusetea.
Ce se intampla daca sirul initial este schimbat?
Ce se intampla cand se sterge obiectul rezultat?

void String::operator+=(const char *sir)
{
[b]String auxiliar;
auxiliar.sir = new char [strlen(this->sir)+1];[/b]
...
}


Motiveaza alegerea tipului pentru variabila auxiliar.

@OC si dani.user. Ce parere aveti de o sub-arie in care sa fie puse temele de la tutoriale? Astfel tutorialele ar fi ceva mai aerisite.

Edited by Cy_Cristian, 15 July 2013 - 10:45.


#27
xyv123

xyv123

    Member

  • Grup: Members
  • Posts: 439
  • Înscris: 01.03.2012
"operatorul[] trebuie neaparat sa arunce exceptie."
Nu trebuie sa arunce exceptie, din aceleasi motive pentru care nici std::string::operator [] nu arunca. Dar poate sa creeze o functie at(), care sa verifice accesele out-of-bounds si sa arunce exceptii daca e cazul.
Ar fi trebuit sa avem:
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;


Edited by xyv123, 15 July 2013 - 10:54.


#28
Cy_Cristian

Cy_Cristian

    Active Member

  • Grup: Members
  • Posts: 1,845
  • Înscris: 22.02.2009
Ne poti explica care sunt motivele pentru care nu se arunca exceptie in caz de OOB in operatorul de indexare al "string"?
Un programel scris prost crapa in VS2008. Acelasi programel merge fara probleme cu gcc.

LE: Reformulare.

Edited by Cy_Cristian, 15 July 2013 - 11:11.


#29
xyv123

xyv123

    Member

  • Grup: Members
  • Posts: 439
  • Înscris: 01.03.2012
Codul client ar trebui fie sa verifice ca parametrul trimis in operator [] nu e out-of-bounds, fie sa foloseasca at().
Motive:
- unul evident, de performanta. Folosind operatorul [], vreau sa accesez caracterul de la un anumit index cat mai rapid. Daca as vrea sa mi se verifice accesul, pot sa folosesc linistit at().
- De obicei, un programator C++ se astepta ca operatorul [] pe secvente sa ofere garantii no-throw.

Edited by xyv123, 15 July 2013 - 11:21.


#30
Cy_Cristian

Cy_Cristian

    Active Member

  • Grup: Members
  • Posts: 1,845
  • Înscris: 22.02.2009
Pe mine ma sperie partea cu bold si italic de aici destul de mult:

Quote

Exception safety
If pos is not greater than the string length, the function never throws exceptions (no-throw guarantee).
Otherwise, it causes undefined behavior.

De unde si implementare din VS2008.

#31
xyv123

xyv123

    Member

  • Grup: Members
  • Posts: 439
  • Înscris: 01.03.2012
Mi se pare normal.

Edited by xyv123, 15 July 2013 - 11:27.


#32
adrian93

adrian93

    Active Member

  • Grup: Members
  • Posts: 1,740
  • Înscris: 29.10.2009

View PostCy_Cristian, on 15 iulie 2013 - 10:45, said:

@adrian93. Ai o mica problema la cod. Norocul tau este ca aceeasi problema a existat si la CString in versiunile initiale. Deci esti intr-o companie selecta Posted Image.
La ce anume te referi mai exact? La subString :)?

#33
Cy_Cristian

Cy_Cristian

    Active Member

  • Grup: Members
  • Posts: 1,845
  • Înscris: 22.02.2009
@xyv123.
Eu sunt de principiu ca executia unui program trebuie sa fie determinista.

@adrian93.
Incearca sa faci.
a=a;
a+=a;

Edited by Cy_Cristian, 15 July 2013 - 12:14.


#34
adrian93

adrian93

    Active Member

  • Grup: Members
  • Posts: 1,740
  • Înscris: 29.10.2009
@Cy_Cristian: Ok, mulțumesc pentru observație, am modificat += astfel încât să meargă și în cazul a+=a :).

#35
xyv123

xyv123

    Member

  • Grup: Members
  • Posts: 439
  • Înscris: 01.03.2012

View PostCy_Cristian, on 15 iulie 2013 - 12:13, said:

@xyv123.
Eu sunt de principiu ca executia unui program trebuie sa fie determinista.
Asa e in C++ ... unele bug-uri duc la comportament nedefinit.

Edited by xyv123, 15 July 2013 - 12:50.


#36
alexuts56

alexuts56

    Junior Member

  • Grup: Members
  • Posts: 175
  • Înscris: 27.12.2010
@Cy_Cristian: Multumesc! Am inteles unde am gresit, mai putin faza cu supraincarcarea operatorului de atribuire.

Adica de ce e gresit daca nu returnez nimic? Care-i copia inutila?

Anunturi

Chirurgia cranio-cerebrală minim invazivă Chirurgia cranio-cerebrală minim invazivă

Tehnicile minim invazive impun utilizarea unei tehnologii ultramoderne.

Endoscoapele operatorii de diverse tipuri, microscopul operator dedicat, neuronavigația, neuroelectrofiziologia, tehnicile avansate de anestezie, chirurgia cu pacientul treaz reprezintă armamentarium fără de care neurochirurgia prin "gaura cheii" nu ar fi posibilă. Folosind tehnicile de mai sus, tratăm un spectru larg de patologii cranio-cerebrale.

www.neurohope.ro

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate