Professional Documents
Culture Documents
++L10 - Reference, Pass - by - Reference 2022
++L10 - Reference, Pass - by - Reference 2022
რეფერენსი
reference არის ობიექტის ფსევდონიმი (alias), ანუ, მარტივად რომ ვთქვათ, იმ ობიექტის
მეტსახელი, რომელსაც იგი მიუთითებს. მაგალითად,
int j = 10, k;
int &i = j; // განაცხადი i მითითებაზე (ფსევდონიმზე)
განაცხადი აღნიშნავს, რომ i წარმოადგენს j-ს კიდევ ერთ სახელს, ანუ მთელი ტიპის i ცვლადის
მისამართი იგივეა, რაც მთელი ტიპის j ცვლადისა ( ე.ი. i და j - ერთი და იგივე მეხსიერების
სახელებია). ცხადია, რომ რეფერენსზე (ფსევდონიმზე) განაცხადისთანავე აუცილებლად უნდა
მოხდეს მისი ინიციალიზება.
შემდეგი ფრაგმენტი
int j = 10, k;
int &i = j; // განაცხადი i რეფერენსზე (მითითებაზე, ფსევდონიმზე)
cout << j << " " << i; // დაიბეჭდება 10 10
k = 121;
i = k;
// i-ს მიენიჭა k-ს მნიშვნელობა, ე.ი. j-ც გახდება k-ს ტოლი
cout << j<< " " << i; // დაიბეჭდება 121 121
i++;
cout << j<< " " << i; // დაიბეჭდება 122 122
79
ფუნქციის პარამეტრი წარმოადგენს reference–პარამეტრს. ეს აუცილებელია, რადგან ფუნქციის
დანიშნულებაა ჩაწეროს ვექტორში კლავიატურიდან შემოსული მთელი რიცხვები, ანუ ფუნქციის
fillVector(a);
გამოძახების შედეგად a ვექტორი უნდა შეიცვალოს.
ფუნქცია printVector ბეჭდავს ვექტორს. რადგან a ვექტორის ზომა შეიძლება იყოს დიდი, ამ
ფუნქციის პარამეტრი მიზანშეწონილია გამოვიყენოთ reference სახით, მიუხედავად იმისა რომ
ვექტორის შეცვლას არ ვგეგმავთ. ასეთ შემთხვევებში უნდა ვიყოთ ფრთხილად – თუ ფუნქციის
ტანში შემთხვევით შეიცვლება x ვექტორის ელემენტი (ელემენტები), ეს შეგვიცვლის a ვექტორს.
ენაში გვაქვს დაცვის მექანიზმი, რომელიც მსგავსი შეცდომებისგან გვიცავს –
const reference პარამეტრის გამოყენება:
void printVector(const vector<int>& x);
ახლა თუ ნებით ან უნებლიეთ შევეცდებით a ვექტორის შეცვლას, კომპილერი გამოიტანს
შეცდომის შესახებ გზავნილს: 'x' : you cannot assign to a variable that is const.
იგივეა რაც
*&area = 11*11;
როგორც ვიცით, *&area იგივეა რაც area. ამგვარად, ფუნქციის ტანის პირველმა სტრიქონმა
გადაცემულ მისამართზე, მთავარ პროგრამაში შექმნილ area ცვლადში ჩაწერა ამ კვადრატის
ფართობი. ანალოგიურად სრულდება ფუნქციის მეორე სტრიქონი.
რეფერენსების საშუალებით შექმნილი კოდი უფრო მარტივი გასაგებია (ფორმალურად მაინც):
void kvadrati(const double side, double &s, double &p)
{
s = side * side;
p = 4 * side;
}
int main()
{
double area, perimeter;
kvadrati(11, area, perimeter);
cout << "tu kvadratis gverdi aris 11-is toli, fartobi = "
<< area << ", perimetri = " << perimeter << endl;
}
აქაც, გამოძახება
kvadrati(11, area, perimeter);
იგივეა რაც
area = 11 * 11;
82
string w;
while(cin >> w)
a.push_back(w);
printVector(a);
cout << "a.back() = " << a.back() << endl;
a.back() = "runrunrun";
printVector(a);
}
vector კლასის მეთოდი .back()საშუალებას გვაძლევს, რომ გავსინჯოთ და შევცვალოთ
ვექტორის ბოლო ელემენტი. ამ პროგრამის შესრულების ერთი შესაძლო ვარიანტი შემდეგია:
ეს მეთოდი (ანუ კლასის წევრი ფუნქცია) ამ შედეგს აღწევს იმის წყალობით რომ აბრუნებს
რეფერენსს ცვლადზე.
ვცადოთ იგივე შედეგის მიღწევა გლობალური ფუნქციის შექმნის საშუალებით:
void printVector(const vector<string> &s)
{
for(int i{}; i < s.size(); i++)
cout << s[i] << '\t';
cout << endl;
}
string& back(vector<string> &s)
{
return s[s.size()-1];
}
int main()
{
vector<string> a;
string w;
while(cin >> w)
a.push_back(w);
printVector(a);
cout << "back(a)= " << back(a) << endl;
back(a) = "runrunrun";
printVector(a);
}
მისი შედეგია:
გამოძახება
back(a) = "runrunrun";
აკეთებს შემდეგ საქმეს: მარჯვენა მხარეში ბრუნდება რეფერენსი ვექტორის ბოლო ელემენტზე,
ანუ მარჯვენა მხარე არის ვექტორის ბოლო ელემენტის ახალი სახელი. შედეგად, მას შეგვიძლია
მივანიჭოთ იგივე ტიპის ახალი მნიშვნელობა.
მეორე მაგალითად, განვიხილოთ საკითხი, თუ როგორ დავაბრუნებინოთ ერთ ფუნქციას ერთზე
მეტი მნიშვნელობა. მაგალითად, კვადრატის ფართობი და პერიმეტრი. აქ ერთი გამოსავალი
83
ასეთია: ასეთი წყვილი, შედგენილი ორი ნამდვილი რიცხვისგან, უნდა განვიხილოთ ერთ
ობიექტად. მაშინ მისი დაბრუნება შეგვიძლია return -ის საშუალებით.
ჩვენ უკვე განვიხილეთ მონაცემთა რამდენიმე ტიპი (ვექტორი, სტრინგი), რომლებიც შექმნილია
კლასის საშუალებით. C++ ენაში არის კლასი pair <ტიპი1, ტიპი2>, რომელსაც შეუძლია შექმნას
ორი სხვადასხვა ტიპისგან წყვილი. წყვილის პირველ და მეორე ელემენტზე წვდომა ხორციელდება
სახელის და არა ინდექსის საშუალებით. შემდეგი კოდი გვიჩვენებს მცირე ნაწილს იმისა, თუ
როგორ შეიძლება ამ კლასის გამოყენება:
#include <iostream>
#include <vector>
using namespace std;
pair<double,double> kvadrati(double side)
{
pair<double,double> point;
point.first = side * side;
point.second = 4 * side;
return point;
}
int main()
{
auto k = kvadrati(11);
cout << "tu gverdi = 11, fartobi = " << k.first
<< ", perimetri = " << k.second << endl;
}
შედეგი იგივეა, რაც რეფერენსის და პოინტერის გამოყენების შემთხვევაში:
tu gverdi = 11, fartobi = 121, perimetri = 44
Press any key to continue . . .
#include <iostream>
#include <vector>
using namespace std;
void printVec(const vector<int>& );
84
void changeVec(vector<int>& ){
int main()
{
vector<int> a { 1, -2, 3, -4, 5, 6, -7, 8, 9, -10 };
printVec(a);
changeVec(a);
cout << "After change ";
printVec(a);
}
void printVec(const vector<int>& x)
{
cout << "Vector is\n";
for (const int& elem : x) // ან for (const auto& elem : x)
cout << elem << ' ';
cout << endl;
}
void changeVec(vector<int>& x)
{
for (auto &y : x) // ან for (int &y : x)
{
y = pow(y, 3.);
}
}
პროგრამის შესრულების შედეგია: Vector is
1 -2 3 -4 5 6 -7 8 9 -10
After change Vector is
1 -8 27 -64 125 216 -343 512 729 -1000
Press any key to continue . . .
85