سلام!
در جلسه های قبلی شما کمی با چگونگی بازتعریف عمل گر ها آشنا شدید. حالا این جلسه می خواهیم با کمک متغیرهای مرجع (که با آن ها در جلسه ی پیش آشنا شدید) عمل گر های بیشتری را تغییر دهیم.
فرض کنید می خواهیم عمل گر += را پیاده سازی کنیم. برای این کار باید از متغیرهای مرجع استفاده کنیم. می توانید کد مربوط به آن را در کد زیر ببینید.
#include <iostream>
#include <cstdio>
using namespace std;
class Point{
friend void set(Point*, double = 0, double = 0);
private:
double _x, _y;
public:
Point(double = 0, double = 0);
double x() const;
double y() const;
void setX(double);
void setY(double);
void print();
};
Point::Point(double x, double y){
this->setX(x);
this->setY(y);
}
void Point::setX(double x){
this->_x = x;
}
void Point::setY(double y){
this->_y = y;
}
double Point::x() const{
return this->_x;
}
double Point::y() const{
return this->_y;
}
void Point::print(){
printf("(%g, %g)", this->x(), this->y());
}
Point operator+(Point p1, Point p2){
return Point(p1.x() + p2.x(), p1.y() + p2.y());
}
Point operator-(Point p1, Point p2){
return Point(p1.x() - p2.x(), p1.y() - p2.y());
}
Point operator*(Point p1, Point p2){
return Point(p1.x() * p2.x(), p1.y() * p2.y());
}
Point operator/(Point p1, Point p2){
return Point(p1.x() / p2.x(), p1.y() / p2.y());
}
Point operator+(int a, Point p){
return Point(p.x() + a, p.y() + a);
}
Point operator+(Point p, int a){
return Point(p.x() + a, p.y() + a);
}
bool operator>(Point p1, Point p2){
if (p1.x() > p2.x())
return true;
if (p1.y() > p2.y())
return true;
return false;
}
bool operator==(Point p1, Point p2){
return p1.x() == p2.x() && p1.y() == p2.y();
}
bool operator!=(Point p1, Point p2){
return !(p1 == p2);
}
bool operator<(Point p1, Point p2){
return !(p1 > p2) && !(p1 == p2);
}
bool operator<=(Point p1, Point p2){
return !(p1 > p2);
}
bool operator>=(Point p1, Point p2){
return !(p1 < p2);
}
void operator+=(Point &p1, const Point &p2){
p1.setX(p1.x() + p2.x());
p1.setY(p1.y() + p2.y());
}
int main(){
Point p1(12, 43);
Point p2(54, 12);
p1 += p2;
p1.print();
return 0;
}
توضیح: ورودی تابع دو متغیر مرجع از جنس Point است. دلیل مرجع بودن ورودی اوّلی احتمالا مشخّص است؛ ما می خواهیم خود متغیر را تغییر دهیم نه یک کپی از آن را. برای همین هم ورودی را مرجع تعریف می کنیم. ورودی دوم هم مرجع تعریف شده زیرا همان طور که قبلا گفتیم، استفاده از مرجع ها به عنوان ورودی تابع خیلی سریع تر است. نیازی هم به خروجی نداریم زیرا ورودی را تغییر داده ایم.
به کمک همین کار می توانید بقیه ی عمل گر ها (-=، /= و ...) را پیاده سازی کنید. حال بیایید cin و cout را هم برای Point تعریف کنیم.
قبل از این که این عمل گر ها را تعریف کنیم، لازم است به طرز عمل کرد cin و cout بپردازیم.
cin یک متغیر از نوع istream و cout یک متغیر از نوع ostream است. فرض کنید در برنامه ی خود نوشته اید
cin >> a;
خروجی این خط خود cin است (یعنی یک istream). فایده ی این کار این است که به خاطر همین شما می توانید چند بار از cin (و cout) استفاده کنید. مثلا در این خط کد:
cin >> a >> b;
برنامه ابتدا a را از ورودی می خواند و سپس به جای cin >> a خود cin را قرار می دهد. پس یک cin >> b می ماند که باعث می شود b از ورودی خوانده شود. طرز کار cout هم همین طور است.
حالا بیایید به پیاده سازی cin و cout برای Point بپردازیم. تا این جا فهمیده ایم که تعریف تابع باید چیزی مثل کد زیر باشد:
istream operator>>(istream input, Point &p);
ولی اگر این کد را امتحان کنید، می بینید که کار نمی کند. دلیل آن هم این است؛ شما در ورودی یک کپی از cin را ورودی گرفته اید و یک کپی از cin لزوما مانند cin از ورودی مقدار نمی گیرد! پس هم در ورودی و هم در خروجی باید یک مرجع تعریف کنید، یعنی:
istream &operator>>(istream &input, Point &p);
در کد زیر این عمل گر را هم به Point اضافه کرده ام.
#include <iostream>
#include <cstdio>
using namespace std;
class Point{
friend void set(Point*, double = 0, double = 0);
friend istream &operator>>(istream&, Point&);
private:
double _x, _y;
public:
Point(double = 0, double = 0);
double x() const;
double y() const;
void setX(double);
void setY(double);
void print();
};
Point::Point(double x, double y){
this->setX(x);
this->setY(y);
}
void Point::setX(double x){
this->_x = x;
}
void Point::setY(double y){
this->_y = y;
}
double Point::x() const{
return this->_x;
}
double Point::y() const{
return this->_y;
}
void Point::print(){
printf("(%g, %g)", this->x(), this->y());
}
Point operator+(Point p1, Point p2){
return Point(p1.x() + p2.x(), p1.y() + p2.y());
}
Point operator-(Point p1, Point p2){
return Point(p1.x() - p2.x(), p1.y() - p2.y());
}
Point operator*(Point p1, Point p2){
return Point(p1.x() * p2.x(), p1.y() * p2.y());
}
Point operator/(Point p1, Point p2){
return Point(p1.x() / p2.x(), p1.y() / p2.y());
}
Point operator+(int a, Point p){
return Point(p.x() + a, p.y() + a);
}
Point operator+(Point p, int a){
return Point(p.x() + a, p.y() + a);
}
bool operator>(Point p1, Point p2){
if (p1.x() > p2.x())
return true;
if (p1.y() > p2.y())
return true;
return false;
}
bool operator==(Point p1, Point p2){
return p1.x() == p2.x() && p1.y() == p2.y();
}
bool operator!=(Point p1, Point p2){
return !(p1 == p2);
}
bool operator<(Point p1, Point p2){
return !(p1 > p2) && !(p1 == p2);
}
bool operator<=(Point p1, Point p2){
return !(p1 > p2);
}
bool operator>=(Point p1, Point p2){
return !(p1 < p2);
}
Point &operator+=(Point &p1, Point p2){
p1.setX(p1.x() + p2.x());
p1.setY(p1.y() + p2.y());
return p1;
}
istream &operator>>(istream &input, Point &p){
input >> p._x >> p._y;
return input;
}
int main(){
Point p1(12, 43);
Point p2;
cin >> p2;
p1 += p2;
p1.print();
return 0;
}
حالا می توانید تمرین های زیر را انجام دهید.
۱. عمل گر های +=، -= و ... را برای Point تعریف کنید.
۲. cin و cout را برای Point تعریف کنید.
نکته: سعی کنید تا جایی که می توانید از متغیرهای مرجع استفاده کنید. فعلا همین تمارین برای این جلسه کافی هستند. اگر سوالی راجع به تمرین ها و یا درس داشتید، در قسمت نظرات مطرح کنید.
موفق باشید!