3. Псевдоними. Предефиниране на функции

 

Ι. Псевдоними.

Псевдонимът представлява неявен указател, който играе ролята на друго име за дадена променлива. Съществуват 3 начина, по които може да се използва даден псевдоним:

·        Псевдонимът може да бъде предаван на функция

·        Псевдонимът може да бъде връщан като резултат от функция

·        Може да бъде създаван независим псевдоним

 

1.1.   Псевдоним като параметър на функция

Когато един обект се предава като параметър на функция посредством подразбиращото се обръщение по стойност, се създава копие на този обект. Въпреки, че конструкторът на параметъра не се извиква, все пак се извиква неговият деструктор, когато функцията върне резултат. В някои случаи това може да доведе до сериозни проблеми – напр., ако деструкторът освобождава някаква заделена памет.

Едно от решенията за този проблем е обекти да се предават чрез псевдоними. Когато обекта се подава чрез псевдоним, не се създава копие на обекта, а следователно не се извиква и деструкторът, когато функцията върне резултат. Промените, които се направят с обекта в рамките на функцията се запазват и след излизането от функцията. Ако обектите не трябва да бъдат променени от функцията, то се използват константни псевдоними.

Псевдонимът не е указател. Следователно, когато един обект се предава чрез псевдоним, операторът за достъп до член си остава точка(.), а не стрелка(->).

 

Задача 1. Предаване на константен псевдоним на обект като параметър на функция.

 

#include<iostream.h>

#include<math.h>

 

class point           //Клас точка

{  private:

     double x;

     double y;

   public:

     point(double xcoord, double ycoord);            //Конструктор с два параметъра     

     void print();                               //Печат на точка

     double dist(const point &p1, const point &p2); //Разстояние между две точки

     ~point();                                 //Деструктор

};

point::point(double xcoord, double ycoord)    //Конструктор с два параметъра

{

  cout << ”Creating Point( << xcoord << ”,” << ycoord << ) << endl;

  x = xcoord;

  y = ycoord;

}

void point::print()         //Печат на точка

{

  cout << ”Point(” << x << ”,” << y << ”)”;

}

double point::dist(const point &p1, const point &p2)      // Разстояние между две точки

{

  return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));

}

point::~point() //Деструктор

{ cout << ”Destructing ”;

  print();

  cout << endl;

}

void main()

{ point a(3,4), b(10,4);      //Обекти от тип Точка

  cout << ”Distance between ”; a.print();

  cout << ” and ”; b.print();

  cout << ” is ” << a.dist(a,b) << endl;

}

 

   Резултати:

Създава се Точка(3,4)

Създава се Точка(10,4)

Разстоянието между Точка(3,4) и Точка(10,4) е 7

Разрушава се Точка(10,4)

Разрушава се Точка(3,4)

1.2.   Псевдоним на обект като върнат резултат от функция.

Функция може да върне псевдоним на обект като резултат. Функция, която връща псевдоним като резултат, може да се използва и от лявата страна на оператора за присвояване.

 

 

Задача 2. Следната програма създава клас за масив, който автоматично прави проверка за границите на масива. Класа за масив съдържа 2 основни функции – една, която съхранява информацията от масива, и друга, която извлича информацията. Тези функции могат да проверяват по време на изпълнение дали не се надхвърлят границите на масива.

 

 

#include<iostream.h>

#include<stdlib.h>

 

class array {

     int size;

     char *p;

  public:

     array(int num);

     ~array() { delete [] p; }

     char &put(int i);

     char get(int i);

};

 

array::array(int num)

{

  p = new char [num];

  if(!p){

     cout << ”Allocation error\n”;

     exit(1);

  }

  size = num;

}

char &array::put(int i)       //Поставя се нещо в масива 

{

  if(i<0 || i>=size) {

    cout << ”Bounds error!!!\n”;

    exit(1);

  }

  return p[i];           //връща псевдоним за p[i]

}

char array::get(int i)      //Взема се нещо от масива.

{

 if(i<0 || i>=size) {

    cout << ”Bounds error!!!\n”;

    exit(1);

  }

  return p[i];           //връща символ

}

 

int main()

{

  array a(10);

 

  a.put(3) = ’X’;

  a.put(2) = ’R’;

 

  cout << a.get(3) << ”\n” << a.get(2);

  cout << ”\n”;

 

  a.put(11) = ’!’;    //сега се генерира грешка по време на изпълнение

  return 0;

}

 

 

Функцията put() връща псевдоним към елемента на масива, указан от параметъра i. Този псевдоним след това може да бъде използван от лявата страна на конструкция за присвояване, за да съхрани нещо в масива – ако позицията, посочена от i, не е извън границите на масива. Противоположната функция е get() – тя връща стойността, съхранена на позицията посочена от i, ако тя не е извън границите на масива.

В програмата се заделя динамично памет за масива с помощта на new. Това дава възможност да се декларират масиви с различни дължини.

ΙΙ. Предефинирани функции.

Езикът С++ позволява функции с едно и също име да имат различно съдържание и действие. При обръщение към функция с дадено име се зарежда тази от едноименните функции, която отговаря най-точно по брой, тип и ред на аргументите.

 

Задача 3. Да се дефинира отново  клас triangle, като се добави още една член-функция, съименник на член-функция face(), която се отличава по наличието на аргумент и по действие – освен лицето, тя връща и периметъра на триъгълника.

 

#include <iostream.h>

#include <math.h>

class triangle {           

    private:

double a, b, c;                       

    public:

triangle();                     

double face();       //Член-функция face() без аргумент

double face(double *);     //Член-функция face() с един аргумент

void show(char *);

~triangle()  { cout << ”\n\nDestructing object triangle!\n”; }

};

triangle::triangle()        //Дефиниция на конструктора

{do

  { cout << ”\n\nEnter three values for the sides of triangle:\n”;

    cin >> a >> b >> c;

}

while(!((a>0)&&(b>0)&&(c>0)&&((a+b>c)&&((a+c)>b)&&((b+c)>a))));

}

double triangle::face()         //Дефиниция на член-функция face() без аргументи                        

{

double p, s;

p = (a+b+c)/2;

s = sqrt(p*(p-a)*(p-b)*(p-c));

return s;

}

double triangle::face(double *p) //Предефинирана член-функция face()

{

double pp = a+b+c;

*p = pp;     //Връщане на втория резултат чрез аргумент-указател

pp /= 2;

double s;

s = sqrt(pp*(pp-a)*(pp-b)*(pp-c));

return s;

}

void triangle::show(char *name) {

cout << ”Sides of the triangle ” << name << ”:\n”;

cout << ”a=” << a << ”,b=” << b << ”,c=” << c;

}

void main()          

{

triangle tr1;           //Обект tr1; извиква се конструкторът на класа

double p,s;

tr1.show(”tr1”);

cout << ”\nThe face of triangle1 is s=” << tr1.face(); //Зарежда се член-функция face() без

                                                      // аргумент

triangle tr2;           //Обект tr2; извиква се конструкторът на класа

tr2.show(”tr2”);           

s=tr2.face(&p);         //Зарежда се член-функция face() с аргумент  

cout << ”\nThe face of triangle2 is s=” << s << ”, and the perimeter is p=” << p;

}

 

Резултати:

Въведете три стойности за страните на триъгълник: 30 40 50

Страни на триъгълника tr1:

а=30, b=40, c=50

Лицето на триъгълник1 е s=600

Въведете три стойности за страните на триъгълник: 10 10 5

Страни на триъгълника tr2:

а=10, b=10, c=5

Лицето на триъгълник2 е s=24.206, а периметъра е p=25

 

Задачи за самостоятелна работа:

Да се дефинира клас за описание на правоъгълник (по аналог на класа triangle)с две член-функции face(), която се отличава по наличието на аргумент и по действие – освен лицето, тя връща и периметъра на правоъгълника.