نسخه قابل چاپ

بخش ۹ - سربارگذاری عملگرها

در این بخش مباحثی پیرامون سربارگذاری عملگرها مطرح می‌شوند. علاوه بر سربارگذاری عملگرهای ساده مانند + و =+، عملگر درج در جریان‌های خروجی نیز سربارگذاری می‌شود. علاوه بر مباحث مربوط به سربارگذاری عملگرها، توابع عضو ثابت و همچنین توابع دوست نیز مورد اشاره قرار می‌گیرند. مثال‌های این بخش پیاده‌سازی یک تایپ برای اعداد مختلط هستند.

فهرست مثال‌ها

اعداد مختلط بدون سربارگذاری عملگرها

در این بخش کلاس Complex برای استفاده از اعداد مختلط تعریف می‌شود. اعمال جمع و افزایش از طریق متدهای عادی قابل اعمال روی اعداد هستند.

#include <iostream>
using namespace std;

class Complex {
public:
    Complex(double r, double i) : real(r), imag(i) {}
    Complex(double r) : real(r), imag(0) {}
    void print() const;

    Complex add(const Complex& c) const;
    void inc(const Complex& c);

    double re() const { return real; }
    double im() const { return imag; }
private:
    double real;
    double imag;
};

Complex Complex::add(const Complex& c) const {
    return Complex(real + c.real, imag + c.imag);
}

void Complex::inc(const Complex& c) {
    real += c.real;
    imag += c.imag;
}

void Complex::print() const {
    cout << real;
    if (imag > 0)
        cout << '+' << imag << 'i';
    else if (imag < 0)
        cout << imag << 'i';
}

int main() {    
    Complex a(1, 2);
    Complex b(4, -2);

    const Complex zero(0,0);
    zero.inc(a);    // compile error
    zero.print();   // OK!

    a.print();          // 1+2i
    b.print();          // 4-2i

    Complex c = a.add(b);
    c.print();          // 5
    
    b.inc(c);           // 9-2i
    b.print();
}
					
سربارگذاری عملگرهای + و =+

در این بخش، دو عملگر + و =+ برای کلاس اعداد مختلط سربارگذاری می‌شوند. با داشتن این عملگرها، این کلاس به شکل خواناتر و راحت‌تری قابل استفاده است.

#include <iostream>
using namespace std;

class Complex {
public:
    Complex(double r, double i) : real(r), imag(i) {}
    Complex(double r) : real(r), imag(0) {}
    
    void print() const;

//  Complex add(const Complex& c) const;
    Complex operator+(const Complex& c) const;
//  void inc(const Complex& c);
    Complex& operator+=(const Complex& c);

    double re() const { return real; }
    double im() const { return imag; }

private:
    double real;
    double imag;

    //پیاده‌سازی سایر بخش‌ها مانند مثال قبل
};

//Complex Complex::add(const Complex& c) const
Complex Complex::operator+(const Complex& c) const
{
    return Complex(real + c.real, imag + c.imag);
}

//void Complex::inc(const Complex& c)
Complex& Complex::operator+=(const Complex& c)
{
    real += c.real;
    imag += c.imag;
    return *this;
}

void Complex::print() const
{
    cout << real;
    if (imag > 0)
        cout << '+' << imag << 'i';
    else if (imag < 0)
        cout << imag << 'i';
}

int main()
{
    Complex a(1, 2);
    Complex b(4, -2);

    // Complex c = a.add(b);
    Complex c = a + b;
    c.print();          // 5
    
    // b.inc(c);            
    b += c;     
    b.print();          // 9-2i
    b.operator+(c);

    (b += c).print();
    c = (b += a) += a;
}
					
چه خواهد شد ...؟
سربارگذاری عملگرهای + برای جمع با یک عدد حقیقی

در این بخش، عملگر + برای جمع یک عدد مختلط با یک عدد حقیقی سربارگذاری شده است. به این ترتیب، می‌توان عباراتی مانند c + 2.5 داشت که در آن c یک عدد مختلط است.

#include <iostream>
using namespace std;

class Complex {
public:
    Complex(double r, double i) : real(r), imag(i) {}
    Complex(double r) : real(r), imag(0) {}
    
    void print() const;

    Complex operator+(const Complex& c) const;
    Complex& operator+=(const Complex& c);
    Complex operator+(double r) const;

    double re() const { return real; }
    double im() const { return imag; }

private:
    double real;
    double imag;
    //پیاده‌سازی سایر بخش‌ها مانند مثال قبل
};

Complex Complex::operator+(double r) const
{
    return Complex(real + r, imag);
}

Complex Complex::operator+(const Complex& c) const
{
    return Complex(real + c.real, imag + c.imag);
}

Complex& Complex::operator+=(const Complex& c)
{
    real += c.real;
    imag += c.imag;
    return *this;
}

void Complex::print() const
{
    cout << real;
    if (imag > 0)
        cout << '+' << imag << 'i';
    else if (imag < 0)
        cout << imag << 'i';
}

int main()
{
    Complex a(1, 2);

    Complex c = a + 2;
    c.print();            // 3+2i 
    c = 2 + a;
}
					
چه خواهد شد ...؟
عملگر + در حالی که سمت چپ آن عدد حقیقی است

در این بخش، عملگر + برای جمع یک عدد مختلط با یک عدد حقیقی سربارگذاری شده است. به این ترتیب، می‌توان عباراتی مانند 2.5 + c داشت که در آن c یک عدد مختلط است.

#include <iostream>
using namespace std;

class Complex {
public:
    Complex(double r, double i) : real(r), imag(i) {}
    Complex(double r) : real(r), imag(0) {}
    
    void print() const;

    Complex operator+(const Complex& c) const;
    Complex& operator+=(const Complex& c);
    Complex operator+(double r) const;

    double re() const { return real; }
    double im() const { return imag; }

private:
    double real;
    double imag;
};
//تعریف کلاس اعداد مختلط مانند مثال قبل

Complex operator+(const double r, const Complex& c)
{
	return Complex(c.re() + r, c.im());
}

Complex Complex::operator+(double r) const
{
    return Complex(real + r, imag);
}

Complex Complex::operator+(const Complex& c) const
{
    return Complex(real + c.real, imag + c.imag);
}

Complex& Complex::operator+=(const Complex& c)
{
    real += c.real;
    imag += c.imag;
    return *this;
}

void Complex::print() const
{
    cout << real;
    if (imag > 0)
        cout << '+' << imag << 'i';
    else if (imag < 0)
        cout << imag << 'i';
}

int main()
{
    Complex a(1, 2);

    Complex c = 2 + a;
    c.print();            // 3+2i 
}
					
عملگر >> برای درج در خروجی

در این بخش، عملگر >> برای درج یک عدد مختلط در یک جریان خروجی سربارگذاری می‌شود.

#include <iostream>
using namespace std;

class Complex {
public:
    Complex(double r, double i) : real(r), imag(i) {}
    Complex(double r) : real(r), imag(0) {}
    
    void print() const;

    Complex operator+(const Complex& c) const;
    Complex& operator+=(const Complex& c);
    Complex operator+(double r) const;

    double re() const { return real; }
    double im() const { return imag; }

private:
    double real;
    double imag;
};
//تعریف کلاس اعداد مختلط مانند مثال قبل

ostream& operator<<(ostream& out, const Complex& c)
{
    out << c.re();
    if (c.im() > 0)
        out << '+' << c.im() << 'i';
    else if (c.im() < 0)
        out << c.im() << 'i';
        
    return out;
}

Complex operator+(const double r, const Complex& c)
{
    return Complex(c.re() + r, c.im());
}

Complex Complex::operator+(double r) const
{
    return Complex(real + r, imag);
}

Complex Complex::operator+(const Complex& c) const
{
    return Complex(real + c.real, imag + c.imag);
}

Complex& Complex::operator+=(const Complex& c)
{
    real += c.real;
    imag += c.imag;
    return *this;
}

void Complex::print() const
{
    cout << real;
    if (imag > 0)
        cout << '+' << imag << 'i';
    else if (imag < 0)
        cout << imag << 'i';
}

int main()
{
    Complex a(1, 2);
    Complex b(4, -2);

    cout << a << b << endl;
    cout << a << b;
}
					
چه خواهد شد ...؟
توابع دوست

در این بخش، عملگر >> به عنوان دوست کلاس Complex تعریف می‌شود و در نتیجه می‌تواند به اعضای خصوصی این کلاس دسترسی داشته باشد. طبیعتاً چنین کاری برخلاف اصول برنامه‌نویسی شیءگرا است و مخفی‌سازی اطلاعات را زیر سؤال می‌برد. به همین دلیل استفاده از این امکان جز در موارد خاص توصیه نمی‌شود. یکی از این موراد سربارگذاری عملگر >> است.

#include <iostream>
using namespace std;

class Complex {
public:
    Complex(double r, double i) : real(r), imag(i) {}
    Complex(double r) : real(r), imag(0) {}
    
    void print() const;

    Complex operator+(const Complex& c) const;
    Complex& operator+=(const Complex& c);
    Complex operator+(double r) const;

    double re() const { return real; }
    double im() const { return imag; }

    friend ostream& operator<<(ostream& out, const Complex& c);
private:
    double real;
    double imag;
    //پیاده‌سازی سایر بخش‌ها مانند مثال قبل
};

ostream& operator<<(ostream& out, const Complex& c)
{
    out << c.real;
    if (c.imag > 0)
        out << '+' << c.imag << 'i';
    else if (c.imag < 0)
        out << c.imag << 'i';

    return out;
}

Complex operator+(const double r, const Complex& c)
{
    return Complex(c.re() + r, c.im());
}

Complex Complex::operator+(double r) const
{
    return Complex(real + r, imag);
}

Complex Complex::operator+(const Complex& c) const
{
    return Complex(real + c.real, imag + c.imag);
}

Complex& Complex::operator+=(const Complex& c)
{
    real += c.real;
    imag += c.imag;
    return *this;
}

void Complex::print() const
{
    cout << real;
    if (imag > 0)
        cout << '+' << imag << 'i';
    else if (imag < 0)
        cout << imag << 'i';
}

int main()
{
    Complex a(1, 2);
    Complex b(4, -2);

    cout << a << b << endl;
    cout << a << b;
}

					
تمرین‌های کوتاه
  1. سربارگذاری عملگرها چه فایده‌ای دارد؟
  2. در استفاده از تایپ‌های کتابخانه‌ی استاندارد سی‌پلاس‌پلاس، چه عملگرهای سربارگذاری شده‌ای را دیده‌اید؟
  3. برای کلاس Date که در بخش‌های قبل تعریف شده، عملگرهای مرتبط را سربارگذاری کنید. تعریف کلاس Date را در بخش ۷ یادداشت‌های درس بررسی کنید و هر یک از متدها و توابعی که در آن تعریف شده‌اند و امکان تبدیل به عملگر دارند را به صورت عملگر تعریف کنید.
  4. یک کلاس به نام Rational برای نگهداری اعداد گویا (کسری) تعریف کنید. برای این کلاس انواع عملگرهای محاسباتی را تعریف کنید. مثال‌هایی از این عملگرها می‌تواند چهارعمل اصلی، عملگرهای جایگزینی متناظر آنها (مانند =+)، عملگر درج در خروجی و عملگر تساوی (==) باشد. عملگرهای محاسباتی (مانند جمع) را در سه شکل Rational + Rational، Rational + double و double + Rational تعریف کنید. برای این کلاس دو سازنده تعریف کنید که یکی صورت و مخرج و دیگری فقط صورت را می‌گیرد و مخرج را یک فرض می‌کند.
  5. یک کلاس به نام BigInt تعریف کنید که می‌تواند اعداد صحیح خیلی بزرگ را در خود نگهداری کند (ارقام را در یک بردار نگهدارید). برای این کلاس دو سازنده تعریف کنید که یکی یک عدد صحیح را می‌گیرد و دیگری رشته‌ای که ارقام در آن ذخیره شده‌اند. عملگرهای +، =+، == , >> را برای این کلاس تعریف کنید. عملگر + را در سه شکل BigInt + BigInt، BigInt + int و int + BigInt تعریف کنید. اعضای کلاس را تا جای ممکن به شکل ثابت تعریف کنید. کلاس خود را توسط یک تابع main بیازمایید.
  6. یک کلاس به نام Poly برای نگهداری چندجمله‌ای‌هایی برحسب یک متغیر تعریف کنید. این کلاس حداقل یک سازنده دارد که یک آرایه از اعداد حقیقی را می‌گیرد که ضرایب این چندجمله‌ای هستند به همراه یک عدد صحیح که درجه‌ی چندجمله‌ای می‌باشد. برای این کلاس، عملگرهای + و * را طوری تعریف کنید که بتوان با آنها دو چندجمله‌ای را با هم جمع یا در هم ضرب کرد. نتیجه‌ی این عملگرها یک چندجمله‌ای جدید خواهد بود. برای این کلاس متدی به نام derivative تعریف کنید که مشتق چندجمله‌ای را برمی‌گرداند. عملگر () را نیز برای ارزشیابی چندجمله‌ای به ازای پارامتر معینی به این شکل تعریف کنید: double operator()(double x).