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(), която се отличава по
наличието на аргумент и по действие – освен лицето, тя връща и периметъра на
правоъгълника.