Special Member Functions and Operator Overloading

Constructor

Objenin oluşturulma aşamasında çalışan ve gerekli atamalarla işlemleri yapan fonksiyondur. Sınıfın member variable’larına constructor içerisinde ilk değer ataması yapılır. C++ 11 den itibaren ilk değer atamısını constructor kullanmadan yapabiliriz:

class Air{
  float temperature{321};
};

Constructor delegation

Bir constructor’den başka bir constructor’ı çağırıp kod tekrarını minimize etmek amaçlanır.

class Air {
  float temperature;
  float velocity;
  float pressure;
  
public:
  Air(){
    temperature = 321;
    velocity = 0; 
    pressure = 223;
  }
  
  Air(float temperature) : Air() {
    this->temperature = temperature; 
  }  
    
};

Constructor types

  • Default Constructor
  • Parameterized Constructor
  • Copy Constructor
  • Move Constructor

Copy Constructor

Var olan bir nesneden başka bir nesneyi initialize ederken kullanılır. Tıpkı default constructor gibi implicit olarak compiler tarafından sınıfa eklenir. Lakin bazı durumlarda nesnenin istediğimiz gibi kopyalanması için kendimizi yazarız.

class Air {
  Air(const Air& other); // copy constructor
};

int main(){
  Air a1;
  Air a2(a1); // copy constructor called 
  Air a3 = a1; // also copy constructor called because this is not an assignment 
  
  // fonksiyon çağrılarında ve returnlerde copy constructor çağrılabilir. 
}

Assignment Operator

x = y; // x nesnesinin assignment operatörü çağrılır. 

// birden fazla atama operatörü varsa aşağıdaki mantıkla çalışır
x = y = z; 
x = (y = z);


// Atama operatörü:
Air& operator =(const Air& air){
  velocity = air.velocity;
  temperatture = air.temperature;
  return *this;
}

Synthesized Member Functions

The six special members functions described above are members implicitly declared on classes under certain circumstances:

Member functionimplicitly defined:default definition:
Default constructorif no other constructorsdoes nothing
Destructorif no destructordoes nothing
Copy constructorif no move constructor and no move assignmentcopies all members
Copy assignmentif no move constructor and no move assignmentcopies all members
Move constructorif no destructor, no copy constructor and no copy nor move assignmentmoves all members
Move assignmentif no destructor, no copy constructor and no copy nor move assignmentmoves all members
https://cplusplus.com/doc/tutorial/classes2/

Shallow and Deep Copying

  • Eğer sadece öteki nesnenin pointer adresi kopyalanırsa bu shallow copy olur.
  • Bellekte yeni bir memory allocate edilip data kopyalanırsa bu deep copy olur.

class MyString {
	char * data;
	int size; 
public:
	MyString(string str){
		size = str.size();
		data = new char[size];
		copy(str.begin(), str.end(), data);
	}
	MyString(const MyString& str) {
		size = str.size;
		data = new char[size];
		copy(str.data, str.data + size, data);
	}
	MyString& operator = (const MyString& str) {
		if (&str != this) { // check for self-assignment 
			delete[] data;

			size = str.size;
			data = new char[size];
			copy(str.data, str.data + size, data);
		}
		return *this; 
	}
	
	~MyString() {
		delete[] data;
	}
};

Rule of Three

If a class requires a user-defined destructor, a user-defined copy constructor, or a user-defined copy assignment operator, it almost certainly requires all three.

https://en.cppreference.com/w/cpp/language/rule_of_three

Copy Ellision

In C++ computer programmingcopy elision refers to a compiler optimization technique that eliminates unnecessary copying of objects.

https://en.wikipedia.org/wiki/Copy_elision

Conversion Operators

class Air {
	int i{};
public:

	Air(int n) :i{ n } {}
	//explicit Air(int n) :i{ n } {}

	operator int() const { return i; }
	explicit operator float() const { return 3.5; }

};

int main() {
	Air air = 7; // implicit constructor 

	// implicit conversion & explicit conversion 
	cout << air + 3 << endl; // 10 
	cout << static_cast<float>(air) << endl; // 3.5
}

Default and Delete Keywords

  • Default: default, copy, gibi constructorları sentezlemek için kullanılır.
  • Delete: constructor’ı siler/kullanmayı engeller. Tıpkı bir constructor’ı private yapmak gibi
struct noncopyable
{
  noncopyable() =default; 
  noncopyable(const noncopyable&) =delete;
  noncopyable& operator=(const noncopyable&) =delete;
};

The Friend Keyword

Sınıfın, member fonksiyonu olmayan fonksiyon ve diğer sınıflara; private memberlarına erişime izin vermesidir. Yani bir sınıfın friend fonksiyonu o sınıfa ait olmasa da, o sınıfın private member’larına erişebilir.

class M{
  friend class F;  // Introduces F but doesn't define it
  friend void ChangePrivate( Point & );
};
    
void ChangePrivate ( Point &i ) { i.m_i++; }    
class F {};

Member and Non-member Operators

If you define your operator overloaded function as member function, then the compiler translates expressions like s1 + s2 into s1.operator+(s2)That means, the operator overloaded member function gets invoked on the first operand. That is how member functions work!

But what if the first operand is not a class? There’s a major problem if we want to overload an operator where the first operand is not a class type, rather say double. So you cannot write like this 10.0 + s2. However, you can write operator overloaded member function for expressions like s1 + 10.0.

To solve this ordering problem, we define operator overloaded function as friend IF it needs to access private members. Make it friend ONLY when it needs to access private members. Otherwise simply make it non-friend non-member function to improve encapsulation!

class Sample
{
 public:
    Sample operator + (const Sample& op2); //works with s1 + s2
    Sample operator + (double op2); //works with s1 + 10.0

   //Make it `friend` only when it needs to access private members. 
   //Otherwise simply make it **non-friend non-member** function.
    friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2
}

Read these :
A slight problem of ordering in operands
How Non-Member Functions Improve Encapsulation

https://stackoverflow.com/questions/4622330/operator-overloading-member-function-vs-non-member-function

Prefix and Postfix Operators

// prefix 
++p;
// equivalent of the prefix operator 
p = p + 1;
return p; 


// postfix; 
p++;
// eqivalent of the postfix operator
temp = p;
p = p + 1;
return temp;

// operator overloading of prefix & postfix 
Air& operator ++(){ // prefix
  ++var;
  return *this;
}   
Air operator ++(int t){ // postfix (int is a dummy variable) 
  Air temp(*this);
  ++var;
  return temp;
}

Function Call Operator

Bir nesneyi bir fonksiyon gibi kullanabilmeyi sağlar.

class Functor
{
public:
    int operator()(int a, int b)
    {
        return a < b;
    }
};

int main()
{
    Functor f;
    int a = 5;
    int b = 7;
    int ans = f(a, b);
}

https://learn.microsoft.com/en-us/cpp/standard-library/function-objects-in-the-stl?view=msvc-170

Printing Out Class Member Data

class Date{
    // ...
    friend ostream& operator<<(ostream& os, const Date& dt);
};

ostream& operator<<(ostream& os, const Date& dt)
{
    os << dt.mo << '/' << dt.da << '/' << dt.yr;
    return os;
}

https://learn.microsoft.com/en-us/cpp/standard-library/overloading-the-output-operator-for-your-own-classes?view=msvc-170


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *