Cu tipurile predefinite (în C) se poate lucra aşa de simplu:

  int i = 123;   // Se alocă spaţiu pentru valori de tip "int" (16/32 biţi) 
                 // şi se iniţializează cu valoarea 123
  int k = i + 1; // Se atribuie noii variabile k, valoarea existentă în i mărită cu 1
  cout << k;     // Se emite pe "output" valoarea variabilei k
  ETC...

Păi oare nu s-ar putea lucra tot aşa şi cu tipuri definite de programator? Aceasta ar fi una dintre ideile de plecare, a tehnologiei de programare denumite OOP ("programare orientată pe obiecte"), implementată de majoritatea limbajelor moderne.

De exemplu, fie VECTOR un nou tip de date, desemnând orice tablou unidimensional (vector) în care cele n elemente ale sale sunt numere de tip double. Am vrea să putem scrie declaraţii, atribuiri, etc. la fel cum scriem de obicei pentru tipurile predefinite:

  VECTOR U(10), V(12); // Se alocă spaţiul necesar pentru un vector de 10 medii anuale ale elevului
  cin >> U >> V;       // Se citesc mediile (U trebuie învăţat să citească!)
  cout << U << V;      // Se afişează mediile (U trebuie învăţat să scrie!)
  cout << "media = " << U.media(); // U trebuie înzestrat cu un serviciu care oferă media generală!

De fapt, nu U "trebuie învăţat", fiindcă U (sau V) este unul dintre elevi (unul sau altul dintre obiectele VECTOR posibile) — clasa întreagă, VECTOR, ar trebui să fie "învăţată" să scrie, să citească, să calculeze una sau alta! Dacă la nivelul întregii clase există servicii de citire, scriere, calcule - atunci acestea vor putea fi utilizate şi individual, de către fiecare "elev".

În clasa obiectelor de tip VECTOR ar trebui să creem posibilităţi precum următoarele:
— de a construi un obiect individual (ştiind câte "medii" trebuie să conţină acesta)
— de a disponibiliza spaţiul ocupat de un obiect individual, când acest obiect nu mai este necesar
— de a permite copieri/atribuiri de date între obiectele clasei
— de a înscrie datele proprii unui obiect, pe baza unui set de date exterior obiectului
— de a furniza spre exteriorul obiectului (pentru public), diverse informaţii proprii obiectului
— de a proteja faţă de modificări neautorizate, datele interne ale fiecărui obiect propriu clasei

// "matricep.h" - interfaţa clasei 'matricep' (obiecte de tip "matrice pătratică")

#include <fstream.h>

class matricep {

   // componente private (zone de date şi funcţii inaccesibile din afara obiectului)

   int Dim;       // matrice de tip n×n (Dim = n)
   double** Arr;  // Arr[i] va fi adresa tabloului aferent liniei i

   double** Alloc();  // alocare (funcţie privată)
   void Free();       // eliberarea zonei referite de Arr 
   void Init();       // iniţializare
   
   // metode publice (constructori, destructori, operaţii, operatori)

   public:

   matricep(int=0);        // matricep X(4), Y(); apelează funcţiile private Alloc(), Init()
   matricep(char, int=0);  // matricea unitate: matricep U(' ', 4);
                           // Primul parametru este anonim şi are doar rolul de a
                           // distinge între primul şi al doilea constructor!

   matricep(matricep&);    // copiere: matricep A(4); ...; matricep X(A); matricep Y = A;
   matricep& operator=(matricep&); // atribuire: X = Y = A+B; foloseşte Free()

   ~matricep();    // destructor; apelează Free()

   double det();   // returnează determinantul matricei
   
   double sol_cramer(double*, double*);  // rezolvă un sistem Cramer
                                         // Arr[] fiind matricea coeficienţilor
                                         // (primeşte referinţe la vectorul termenilor liberi
                                         // şi la un vector în care să se înscrie soluţia)

   // operatori de adunare, înmulţire; inserare/extracţie în/din stream
   friend matricep operator+(matricep&, matricep&);
   friend matricep operator*(matricep&, matricep&);
   
   friend istream& operator>>(istream&, matricep&);
   friend ostream& operator<<(ostream&, matricep&);

};


// "matricep.cpp" - implementarea metodelor clasei 'matricep'

#include "matricep.h"

double** matricep::Alloc() {
    if(!Dim) return 0; 
    double** A = new double* [Dim]; // A este adresa unui tablou de pointeri (la liniile matricei)
    for(int i = 0; i < Dim; i++)
	A[i] = new double [Dim];   // A[i] este adresa tabloului de valori de pe linia i
    return A;
}
// OBS. a observa ordinea în care se fac alocările.
// Eliberarea (dealocarea) va urma ordinea inversă.

void matricep::Init() { 
    for(int i = 0; i < Dim; i++)
	for(int j = 0; j < Dim; j++)
	    Arr[i][j] = 0;
}
// OBS. de obicei, memoria alocată în HEAP trebuie iniţializată fiindcă alocare/dealocare înseamnă
// doar operaţii (rapide) de consemnare a limitelor zonei alocate,
// fără a implica nici o acţiune asupra conţinutului acelei zone.

void matricep::Free() {   // eliberarea memoriei ocupate de Arr[] în Heap
    if(Dim) {
	for(int i = 0; i < Dim; i++)
	    delete []Arr[i]; // Întâi "şterge" fiecare linie.
	delete []Arr;        // Apoi, şterge pointerii liniilor.
    }                        // (ordinea dealocării este inversă ordinii alocării)
    Dim = 0; Arr = 0;
}

matricep::matricep(int n) {  // construieşte (alocă spaţiu, iniţializează) o matrice pătratică,
    Dim = n;                 // în urma unor declaraţii de forma: 
    Arr = Alloc();           // matricep A(5); sau: matricep A(5), B(5);
    Init();
}

matricep::matricep(char, int n) { // matricea unitate de ordinul n
    Dim = n;                      // Primul parametru este nefolosit (şi lăsat ca "anonim") -
    Arr = Alloc();                // având rolul de a distinge faţă de constructorul precedent!
    Init();
    for(int i = 0; i < Dim; i++)  // iniţializează 1 pe diagonala principală
	Arr[i][i] = 1;
}

matricep::matricep(matricep &A) { // Construieşte o matrice pătratică prin copierea datelor
    Dim = A.Dim;                  // din matricea A a cărei adresă e transmisă ca parametru.
    Arr = Alloc();                // De exemplu:
    for(int i = 0; i < Dim; i++)      // matricep H(5);
	for(int j = 0; j < Dim; j++)  // cin >> H;      // citeşte H.Arr[i][j]
	    Arr[i][j] = A.Arr[i][j];  // matricep T(H); // construieşte T, copiind din H
}

matricep::~matricep() { // destructor 
    Free();             // invocă serviciul privat Free()
}

matricep& matricep::operator=(matricep& A) { // operator de atribuire
    if(this != &A) {   // a nu atribui un obiect lui însuşi!
	Free();        // Atribuirea A = B, unde A şi B sunt "matricep" decurge astfel:
	Dim = A.Dim;   // întâi se eliberează datele existente în A; apoi se copiază în A
	Arr = Alloc(); // datele din B (după alocarea necesară).
	for(int i = 0; i < Dim; i++)
	    for(int j = 0; j < Dim; j++)
		Arr[i][j] = A.Arr[i][j];
    }
    return *this;
}

double matricep::det() {
   double d = 1; int L, C, i, k;
   double** a = Alloc();        // a[] este o copie de lucru a Arr[]
   for(i = 0; i < Dim; i++)     //  (ca să nu modifice Arr[]!)
       for(k = 0; k < Dim; k++)
	   a[i][k] = Arr[i][k];
   for(C = 0; C < Dim; C++) {
       // caută pe coloana C un element nenul (primul găsit)
       // în vederea micşorării erorilor de aproximare, ar trebui căutat
       // NU "primul", ci elementul de valoare absolută maximă!
       for(L = C; L < Dim, !a[L][C]; L++); // avem a[L][C]!=0 (dacă L<Dim)
       if(L == Dim) return 0; // pe coloana C toate elementele sunt 0
       if(L != C) {  // interschimbă linia C cu linia L 
	             // (fără a "interschimba" şi zerourile de pe poziţiile 0..C-1)
	   d = -d;   // schimbând între ele două linii, determinantul îşi schimbă semnul
	   for(k = C; k < Dim; k++) {
	       double t = a[C][k];
	       a[C][k] = a[L][k];
	       a[L][k] = t;
	   }
       }
      // înmulţeşte corespunzător linia C şi adaugă liniilor dedesubt (obţinând 0 în coloana C)
       for(i = C + 1; i < Dim; i++)
	   for(k = C + 1; k < Dim; k++)
	       a[i][k] -= a[C][k] * a[i][C] / a[C][C];
   }
   // s-a obţinut matrice triunghiulară (dedesubtul diagonalei principale avem 0)
   for(i = 0; i < Dim; i++)
       d *= a[i][i];
   // eliberează zona ocupată de a[]
   for(i = 0; i < Dim; i++)
       delete []a[i];
   delete []a;
   return d;
}

double matricep::sol_cramer(double* B, double* x) {
// B[] este vectorul termenilor liberi; x[] va memora soluţiile
// B[] şi x[] trebuie alocate/dealocate de către apelant
    double d = det(); int i,j,k;
    if(d) {
	for(i = 0; i < Dim; i++) {
	    matricep dx(Dim); // copie locală a matricei sistemului
	    for(k = 0; k < Dim; k++)
		for(j = 0; j < Dim; j++)
		    dx.Arr[k][j] = Arr[k][j];
	    for(j = 0; j < Dim; j++) // pune B[] în coloana de rang i
		dx.Arr[j][i] = B[j];
	    x[i] = dx.det() / d; // soluţia de rang i
	}
    }
    return d; // dacă 0, atunci vom şti că sistemul nu este determinat
}

matricep operator+(matricep& A, matricep& B) {
    matricep C = A;  // se invocă operatorul de atribuire
    int n = C.Dim;
    double** c = C.Arr, **b = B.Arr;
    for(int i = 0; i < n; i++)
	for(int j = 0; j < n; j++)
	    c[i][j] += b[i][j];    // C.Arr = A.Arr + B.Arr (suma matricelor)
    return C;
}

matricep operator*(matricep& A, matricep& B) {
    int n = A.Dim;
    matricep C(n);
    double** c = C.Arr, **a = A.Arr, **b = B.Arr;
    for(int i = 0; i < n; i++)
	for(int k = 0; k < n; k++) {
	    for(int j = 0; j < n; j++)
		c[i][k] += (a[i][j] * b[j][k]);
	}
    return C;
}

istream& operator>>(istream& f, matricep& A) { // operator de preluare dintr-un stream de input
    for(int i = 0; i < A.Dim; i++)
	for(int j = 0; j < A.Dim; j++)
	    f >> A.Arr[i][j];
    return f;
}

ostream& operator<<(ostream& f, matricep& A) { // operator de înscriere într-un stream de output
    int n = A.Dim;
    for(int i = 0; i < n; i++) {
	f << endl;
	for(int j = 0; j < n; j++)
	    f << A.Arr[i][j] << '\t';
    }
    f << endl; // important! - ţine loc de "f.flush()"
    return f;
}



// exemplu de folosire a clasei 'matricep'

#include "matricep.cpp"
#include <iomanip.h> // pentru formatarea scrierii valorilor 'double'

matricep A(3), E(' ',3);

// determină puterea n a unei matrice pătratice (algoritm Al-Kashî)
matricep alan(matricep& A, int n) {
   if(n == 0) return E;
   if(n % 2) return A * alan(A, n-1);
   matricep S = alan(A, n / 2);
   return S * S;
}

void main() {
   cin>>A;
   ofstream co("con");
   co << setiosflags(ios::fixed);
   co << alan(A,10);
}
// exemplu de folosire a clasei 'matricep' 
// rezolvarea unui sistem liniar Cramer

#include "matricep.cpp"
#include <iomanip.h>
 
int n = 4;
matricep A(n);

void main() { int i;
  cin >> A; // matricea coeficienţilor sistemului
  double* B = new double[n]; // vectorul termenilor liberi
  double* s = new double[n]; // alocare pentru vectorul soluţie
  for(i = 0; i < n; i++) cin >> B[i];
  ofstream co("con");
  co << setiosflags(ios::fixed);
  if(A.sol_cramer(B,s)) {
    for(i = 0; i < n; i++)
       co << s[i] << '\t';
  } else co<<"Nu este compatibil determinat"<<endl;     
  delete []B; // eliberează memoria alocată pt. B[] şi s[]
  delete []s;
}