Î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.
Ne dorim:
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!
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
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__
Î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)
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)
Încercați să extindeți class Point2D la class Point3D (punct în spațiu). Care sunt diferențele?