연산자 오버로딩

킴스코딩클럽·2022년 11월 30일
1

CS기초 시리즈

목록 보기
56/71
  • 연산자가 함수라면에서 출발함
  • 이해하면 매우 편리한 c++의 기능
  • 클래스들끼리 연산을 할 수 있게 만드는 용도
  • 연산자가 멤버로 도착하면 class1.operator(class2);
  • 좌측 피연산자는 this 오른쪽 피연산자는 매개변수 1개
  • const 참조형은 r-value(이름없는객체)를 넘겨줄 때 에러가 발생하기 때문에 사용
  • 상수 참조 = rvalue = anonymous object
  • c++의 캡슐화는 인스턴스(오브젝트)가 아닌 클래스 단위
  • 동일한 클래스라면 다른 인스턴스에 접근 할 수 있음

#include <iostream>
class Point2D
{
private:
	int mX;
	int mY;
public:
	Point2D():Point2D(0, 0) {}
	Point2D(int x, int y):mX(x), mY(y)
	{

	}

	void Print()
	{
		std::cout << "(" << mX << "," << mY << ")" << std::endl;
	}
	Point2D& operator++()
	{
		//멤버는 THIS로 자동으로 넘어옴
		++mY;
		++mX;

		return *this;
	}

	Point2D operator++(int x)
	{
		Point2D temp(mX, mY);

		//이미 위에서 만들어놓은 버전이 잇음
		++(*this); //this는 포인터라서 역참조후 증가시킴

		return temp;
	}
};


int main()
{
	Point2D pt1 {2,3}, pt2 {3,4};

	++pt1;

	// ++(Point2D(3, 4)); => ++1이랑 같은 것 (아무의미없음)

	pt2 = ++pt1;	//	34 34
	pt2 = pt1++;	//	34 23

	pt1.Print();
	pt2.Print();

}

배열 첨자 연산자([ ])

  • 배열 첨자 연산자를 오버로딩함
#include <iostream>
class Point2D
{
private:
	int mX;
	int mY;
public:
	Point2D():Point2D(0, 0) {}
	Point2D(int x, int y):mX(x), mY(y)
	{

	}

	void Print()
	{
		std::cout << "(" << mX << "," << mY << ")" << std::endl;
	}
	int& operator[](int index)
	{
		if ( index == 0 )
		{

			return mX;
		}
		else if ( index == 1 )
		{
			return mY;

		}
		else
		{
			std::cerr << "invalid index!" << std::endl;
		}
		return mY;
		//참조형으로 바뀌어서 리턴값이 리터럴이면안됨
	}
}

};


class MyArray
{
public:
	MyArray(): mArray{}
	{

	}
	//인티젙아입의 대입을 하고싶을 떄
	int &operator[](int index)
	{
		return mArray[index];
	}

private:
	int mArray[10];
};


int main()
{
	Point2D pt1 {2,3}, pt2 {3,4};

	pt1[0] = 0;
	std::cout << pt1[0] << "," << pt1[1] << std::endl;
	//객체에 원하는 기능을 기존의 연산자로 쓸 수 있음

	//대입은 불가능함
	//pt1[0] = 0; 왼쪽 피 연산자가 int(rvalue의 값을 넣었기 때문)
	//x[1] = 0; 값을 저장한 l value여야함 => 참조형이 필요해짐


	MyArray array;

	array[0] = 1;
	std::cout << array[0] << std::endl;
}

형변환 연산자( )

  • myFloat = float(myInteger)
class Point2D
{
private:
	int mX;
	int mY;
public:
	Point2D():Point2D(0, 0) {}
	Point2D(int x, int y):mX(x), mY(y)
	{

	}

	void Print()
	{
		std::cout << "(" << mX << "," << mY << ")" << std::endl;
	}
    
	//암시적 형변환 연산자
	//내부가 변경할 필요 없으니 const
	//추측가능하기 때문에 반환 타입은 없음
	operator float()const //강제로 float안쓰도록 문법이 변함
	{
		return sqrt(mX * mX + mY * mY);
	}

};
int main()
{
float dist = pt1;

	std::cout << dist << std::endl;

	std::cout << (float) pt1 << std::endl;
}   

함수 호출 연산자( )

+functor(함수 객체)

class Point2D
{
private:
	int mX;
	int mY;
public:
	Point2D():Point2D(0, 0) {}
	Point2D(int x, int y):mX(x), mY(y)
	{

	}

	void Print()
	{
		std::cout << "(" << mX << "," << mY << ")" << std::endl;
	}
	
	//함수 호출 연산자 ( )
	//함수 객체(functor
	void operator () ()// 앞은 연산자 기호 뒤는 매개변수
	{
		mX = 0;
		mY = 0;
	}

	void operator () (int x, int y)
	{
		mY = y;
		mX = x;
	}


};

int main()
{	
	
	pt1(); //인스턴스에 ()
	//생성자와 다름
	pt1.Print(); //초기화가 0으로 되어있을 것

	pt1(2, 3);
	pt1.Print();
}

friend???

  • 멤버함수 버전의 연산자 오버로딩이 전역함수 버전보다 더 간단함 (friend기능 사용할 필요 없기 때문)
  • 하지만 friend가 필요한 경우도 있음
  • 피연산자가 우리가 만든 클래스가 아닌 경우
  • 이 떄 private에 접근하는 것이 friend

스트림 삽입 연산자 <<

  • std::cout<<x;
  • cout은 ostream이라는 클래스로 cout이라는 instance가 만들어진 것 (전역변수)
#include<iostream>
class Point2D
{
private:
	int mX;
	int mY;
public:
	Point2D():Point2D(0, 0) {}
	Point2D(int x, int y):mX(x), mY(y)
	{

	}
	friend std::ostream &operator<<(std::ostream &os,const Point2D& pt);

};

//정해저 있음
std::ostream &operator<<(std::ostream &os, const Point2D &pt)
{
	os << "(" << pt.mX << "," << pt.mY << ")";
	return os;
}
//이 연산자는 friend가 아니면 불가능 왜?
//이 클래스는 제공되는 클래스임(코드가 숨겨져있음)=>못 건들임
//그래서 멤버함수로 넣을 수 없음
//전역함수 말고 생성할 수 없음

int main()
{
	Point2D pt1 {2,3}, pt2 {3,4};

	std::cout << pt1 << std::endl;
}
  • 몇가지 연산자들은 오버로딩을 하지 않음 ex. { }

  • std::ostream &operator<<(std::ostream &os, const Point2D &pt)
    cout<<x<<y<<z;
    cout<<y<<;
    cout<<z;

+연속된 점 표기법 => UI
c1. function()
.function1()
.function2()
.function3()

  • std::string str; =>
    c++가 제공하는 클래스 기능으로 만든것
profile
공부 기록용

0개의 댓글