Table of Contents

Tutorial 2.1 - Point2D

În acest tutorial, ne propunem să construim o structură de tip Point2D capabil să rețină coordonatele unui punct în plan și să permită anumite prelucrări pe un set de puncte.

Obiective

Ne dorim:

Dezvoltare

Varianta de bază a lui class Point2D

Vom considera ca variantă de bază un struct care conține două elemente de tip double.

#ifndef __POINT2D__
#define __POINT2D__
 
struct Point2D {
 	double x, y; // coordonatele punctului
};
 
#endif __POINT2D__

Această abordare are dezavantajul că variabilele x și y sunt publice, lucru care nu este dorit în general. O abordare elegantă este următoarea:

#ifndef __POINT2D__
#define __POINT2D__
 
class Point2D {
 private:
 	double x, y; // coordonatele punctului
 
 public:
 	// Metoda setter pentru x
 	void setX(const double& x) {
 		this->x = x;
 	}
 
 	// Metoda setter pentru y
 	void setY(const double& y) {
 		this->y = y;
 	}
 
 	// Metoda getter pentru x
 	double getX() {
 		return x;
 	}
 
	// Metoda getter pentru y
 	double getY() {
 		return y;
 	}
 
};
 
#endif // __POINT2D__

Observați folosirea referințelor și a cuvântului cheie const!

Adaugarea de constructori

Pentru a putea inițializa un punct, mai exact coordonatele punctului, cu anumite valori, putem folosi un constructor. În această situație putem inițializa cu valori prestabilite la compile time (Default Constructor), valori cunoscute la runtime (un constructor cu parametri).

        // Constructor default
 	Point2D() {
 		x = 0;
 		y = 0;
 	}
 
 	// Constructor cu parametri
 	Point2D(const double &x, const double &y) {
 		this->x = x;
 		this->y = y;
 	}
 
 	// Copy-constructor
 	Point2D(Point2D& p) {
 		this->x = p.x;
 

Metoda care implemenetează calculul distanței dintre două puncte este următoarea:

 	// Metoda care calculeaza distanta intre doua puncte in plan
 	double distance(const Point2D &p) {
 		return sqrt( (x - p.x) * (x - p.x) + (y - p.y) * (y - p.y) );
 	}

Atenție! Trebuie inclusă biblioteca cmath pentru a putea utiliza funcția sqrt!

#ifndef __POINT2D__
#define __POINT2D__
 
#include <cmath>
....

Putem testa funcționalitățile implementate cu o sursă foarte scurtă.

#include <iostream>
#include "point2D.h"
 
int main() {
	Point2D A, B;
 
	std::cin >> A >> B;
 
	std::cout << A.distance(B);
 
	return 0;
}

Pentru compilare și rulare in bash folosiți comanda

g++ main.cpp -o main && ./main

Adaugarea de alte elemente (e.g. functii de citire/scriere)

Pentru a putea lucra cu ușurință cu elemente de tip Point2D, putem supraîncărca operatorii de citire/afișare, atribuire, egalitate. De asemenea, întrucât am definit Copy-Constructir și operator de atribuire, se impune definirea unui destructor.

#ifndef __POINT2D__
#define __POINT2D__
 
#include <cmath>
 
class Point2D {
 
  ............
 
 public:
 	// Destructor
 	~Point2D() {
 		// Nu avem memorie de eliberat.
 	}
 
 	// Operator de atribuire
 	Point2D& operator=(const Point2D& p) {
 		this->x = p.x;
 		this->y = p.y;
 		return *this; // intoarce referinta pentru atribuiri inlantuite
 	}
 
	// Operator de egalitate
 	bool operator==(const Point2D& p) {
 		// Testez daca cele doua puncte au coordonate egale.
 		if (x == p.x && y == p.y) {
 			return true;
 		}
 
 		return false;
 	}
 
 	//funcţii operator pentru supraîncărcarea operatorilor de intrare/ieşire  
    //declarate ca funcţii de tip "friend"   
    friend std::ostream& operator<< (std::ostream& out, const Point2D& p);
    friend std::istream& operator>> (std::istream& is, Point2D& p);
};
 
 
std::ostream& operator<<(std::ostream& out, const Point2D& p){
   out << "(" << p.x << "," << p.y << ")"<< std::endl;
   return out;
}
 
std::istream& operator>>(std::istream& in, Point2D& p){
  in >> p.x>> p.y;
  return in;
}
 
#endif // __POINT2D__

Testare si Evaluare

Program de test

În continuare vom face un program care prima dată citește un număr n si un element de tip Point2D, numit p, apoi încă n element de tip Point2D. Se cere să se găsească cel mai apropiat punct (din cele n) față de punctul de referință p.

#include <iostream>
#include <cmath> // pentru abs
#include "point2D.h"
 
int main() {
	int n; // numarul de puncte
	Point2D p; // punctul de referinta
	Point2D *v; // vectorul de puncte dat de la tastatura
 
	//citire
	std::cout << "n = ";
	std::cin >> n;;
 
	std::cout << "p = ";
	std::cin >> p;
 
	v = new Point2D[n];
	for ( int i = 0; i < n; ++i ) {
		std::cout << "v[" << i << "]=";
		std::cin >> v[i];
	}
 
	double minDistance = (1<<30); // initializez distanta minima cu ceva foarte mare
	int index = -1; // indicele celui mai apropiat punct
 
	for ( int i = 0; i < n; ++i) {
		double currentDistance = p.distance(v[i]); //distanta fata de punctul curent
 
		if ( currentDistance < minDistance ) {
			minDistance = currentDistance;
			index = i;
		}
	}
 
        // afisare rezultat
	std::cout << "Cel mai apropiat punct este : " << index << " = " << v[index] << '\n';
 
	//eliberare memorie
	delete[] v;
 
	return 0;
}

Exemplu:

n = 5
p = 0 0
v[0]= 5 5
v[1]=40 5
v[2]= 5 -5 
v[3]= 4 3           
v[4]= 8 8
Cel mai apropiat punct este : 3 = (4,3)

Verificare cu Valgrind

Pentru acelasi test rulat cu

 valgrind ./main 

toata memoria va fi eliberata.

==9360== Memcheck, a memory error detector
==9360== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==9360== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==9360== Command: ./main
.....................
==9360== 
==9360== HEAP SUMMARY:
==9360==     in use at exit: 0 bytes in 0 blocks
==9360==   total heap usage: 13 allocs, 13 frees, 772 bytes allocated
==9360== 
==9360== All heap blocks were freed -- no leaks are possible
==9360== 
==9360== For counts of detected and suppressed errors, rerun with: -v
==9360== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Aprofundare

Încercați să extindeți class Point2D la class Point3D (punct în spațiu). Care sunt diferențele?