10 Nisan 2018 Salı

Arithmetic Operators

Giriş
C++'ta kullanılabilen Arithmetic Operators toplam 10 tane.

1.Assignment,
2.Addition,
3.Subtraction,
4.Unary Plus,
5.Unary Minus,
6.Multiplication,
7.Division,
8.Modulo,
9.Postfix Increment, Prefix Increment,
10.Postfix Decrement, Prefix Decrement

1. Genel Konular

1.1 Arithmetic Operator Metodun Global Veya Üye Metod Olması
Her ikisi de olabilir.

1.2 Arithmetic Operator Metodun Virtual Olması
Bütün metodlar gibi bu operatörler istenirse virtual olabiliyorlar.

1.3 Arithmetic Operator Metodun Bir Sonuç Dönmesi
Şart değil. Şöyle yaparız
#include <iostream>
struct foo {
  void operator+(int x) {
    std::cout << x;
  }
};

int main () {
  foo f;
  f + 3;
}
1.4 Named Operator
Gördüğüm en ilginç kodlardan birisi. Önce bir Pow tanımlanır.
const struct PowOperator {} Pow;

struct PowInvoker
{
  int lhs;
};

PowInvoker operator< (int lhs, PowOperator)
{
  return {lhs};
}

int operator> (PowInvoker lhs, int rhs)
{
  return std::pow(lhs.lhs, rhs);
}

int main()
{
  std::cout << (2 <Pow> 3) << std::endl;
}
Sonra kod şöyle çağrılır.
std::cout << (2 <Pow> 3) << std::endl;
2. Operator Metodları
Şimdi her bir Arithmetic Operator metodlarına teker teker bakalım

2.2. Addition Operator
Açıklaması şöyle.
A binary operator can be overloaded as a non-static member function with one parameter or as a non-member function with two parameters (one of those parameters must be either a class object or a reference to a class object).
Diğer operator metodlarında olduğu gibi ya bir member metod ya da global bir metod tanımlamak gerekir. Her iki yöntem de rvalue dönmelidir ve const olmalıdır.

Global Metod Olarak Tanımlama
Bu operator bir sürü farklı şekilde tanımlanabilir. Global metod parametrelerden birisi class olmadığı için şu şekilde olamaz.
int operator+(int, int);
Örnek
Şöyle yaparız.
Foo operator+(Foo , int);
Foo operator+(Foo& , int);
Foo operator+(int, Foo);
Foo operator+(int, Foo&);
Örnek
Global metod genelde friend tanımlanır ki sınıfın içindeki private alanlara erişebilsin.
class matrix
{
public:

  friend matrix operator+(const matrix &, const matrix &);
};

matrix operator+(const matrix &, const matrix &);
Üye metod Olarak Tanımlama
Bu operator bir sürü farklı şekilde tanımlanabilir.

Örnek
Şöyle yaparız.
ClassName & operator+(ClassName &other)
ClassName operator+(ClassName &other)
Classname operator+(const ClassName &other) const
Classname operator+(const Classname other)
Classname operator+(Classname other)
1. tanımlama referans döndürdüğü için iyi değil. a = b +c hata yapmaya açık hale geliyor.
2. kullanım şekli makul ancak parametre ve metod imzası const değil. const olsa daha iyi.
3. kullanım şekli en klasik olanı. Bu kullanımda a = b + c işlemi rahatlıkla yapılabiliyor.
4. ve 5. kullanım şeklide ise gereksiz kopyalama olduğu için tercih edilmemeli.

Örnek
Şöyle yaparız.
class matrix
{
    public:

        matrix operator+(const matrix &) const;   // member version
};
Örnek
Operatorden virtual metod çağırabiliriz. Böylece sol taraf kalıtan sınıfsa daha özel bir işlem yapabiliriz.
struct Base {
    Base operator+(const Base& other) {
        return add(other);
    }
protected:
    virtual Base add(const Base& other) {
        cout << "Adding in Base's code." << endl;
        return Base();
    }
};

struct Derived : public Base {
protected:
    virtual Base add(const Base& other) {
        cout << "Adding in Derived's code." << endl;
        return Derived();
    }
};

int main() {
    Base b1;
    Base b2;
    Derived d1;
    Derived d2;
    Base res;
    res = b1+b2; // Prints "Adding in Base's code."
    res = b1+d2; // Prints "Adding in Base's code."
    res = d1+b2; // Prints "Adding in Derived's code."
    res = d1+d2; // Prints "Adding in Derived's code."
    return 0;
}

2.4. Unary Minus
Değeri eksi haline çevirir. -a gibi düşünülmelidir. Metodun imzası şöyle. Temporary bir nesne döndürür.
MyClass operator -(MyClass& u)
2.9. Prefix Increment
İskeleti şöyledir.
typename& typename::operator++()
{
   // Change state
   ...

   // Return the object
   return *this;
}
Şöyle yaparız.
Foo& Foo::operator++()   // called for ++i
{
    this->data += 1;
    return *this;
}
Prefix Increment ile ilgili bir açıklama şöyle.
preincrement introduces a data dependency into your code -- the CPU must wait for the increment operation to be completed before its value can be used in the expression."
Hız açısından normalde prefix increment, postfix increment'e tercih edilir. Çok nadir durumlarda prefix increment postfix increment'e tercih edilmez. Elimizde şöyle bir kod olsun.
a = b++ * 2;
Bu kod paralel çalıştırılabilir çünkü çarpma işleminin gerçekleşmesi için b'nin postfix increment işleminin bitmesini beklemeye gerek yoktur. Ancak kod şöyle olsaydı
a = ++b * 2;
Bu kod paralel çalıştırılamazdı, çünkü çarpma işleminin gerçekleşmesi için önce b'nin prefix increment işleminin bitmesi gerekirdi.

C++ ve Çoklu Prefix Increment
C++ ve C arasında bazı farklar var. Şu kod C++'ta derlenir. C'de ise derlenmez.
int main()
{
  int i = 0;
  ++++i;
}
2.10Postfix Increment
İskeleti şöyledir.
typename typename::operator++(int)
{
   // Create a temporary object that is a copy of the current object.
   typename temp(*this):

   // Change state of the current object
   ...

   // Return the temporary object.
   return temp;
}
Yeni bir kopya yaratır. Şöyle yaparız.
Foo Foo::operator++(int ignored_dummy_value)   // called for i++
{
  Foo tmp(*this);   // variable "tmp" cannot be optimized away by the compiler
  ++(*this);
  return tmp;
}


Hiç yorum yok:

Yorum Gönder