IT 프로그래밍/객체지향프로그래밍

[c++] 접근 제어와 캡슐화 & 연산자 오버로딩

기술1 2024. 6. 8. 19:51

private를 통해 접근을 제어하는 이유

private 지정자는 하나의 지정자를 다른 외부로부터 이 클래스를 상대적으로 독립성을 가지게 해주는 역할을 합니다. 코딩을 하다가 어떤 이유로 변수의 이름 같은 경우를 바꿔야하는 경우가 발생합니다. 하나를 바꾸게 되면 코드 전체를 훑어가면서 이름을 다 바꿔줘야 합니다. 

 

어떤 변수나 이름을 바꾸게 되면 그 파급효과가 프로그램의 전체에 영향을 미칠 수 있습니다. 모든 부분을 찾아서 해줘야 하지만 클래스에 데이터 멤버를 private로 할 경우 private 멤버는 이 클래스 내부에서만 접근이 가능하므로 클래스 외부에 대해서는 신경 쓸 필요가 없어집니다. 

 

상대적인 독립성을 가진다는 간단한 예입니다. 

 

접근할 수 없는 멤버들은 최소화해주면서 만들어주면 됩니다. 

 

public 멤버를 활용한 방법

get_x(), get_y()를 통해 private에 있는 변수를 가져와줄 수 있습니다. 클래스 외부에서는 이 메서드를 사용하여 x , y 좌표를 엑세스하도록 변경해주도록 해야 합니다. 

 

데이터 캡슐화

모든 데이터 멤버를 private로 만들고 필요한 경우에 public한 get/set 메서드를 제공합니다. 이렇게 하면 객체가 제공해주는 메서드를 통하지 않고서는 객체 내부의 데이터에 접근할 수가 없습니다. 이것을 data encapsulation 혹은 information hiding이라고 부릅니다. 

 

class Date {
public:
	int year, month, day;
	Date(int y, int m, int d) : year(y), month(m), day(d) {}
};

 

연산자 오버로딩

class Date {
public:
	int year, month, day;
	Date(int y, int m, int d) : year(y), month(m), day(d) {}

	Date d1(2024, 2, 20), d2(2011, 9, 28);

	if (d1 == d2)
	{
	}
	else if (d1 < d2)
	{
	}

	Date d3 = d2 + 10;
	d2++;

	int diff = d1 - d2;
};

이런 연산이 가능하도록 만들려면 어떻게 해야 할까요?

date를 더하고 빼는 거는 일반 연산자로는 불가능한데요.

 

이럴 때 오버로딩 연산자를 통해 존재하는 연산자들에 새로운 의미를 부여해주어야 합니다. 

 

	bool operator<(Date& rhs)
	{
		return year < rhs.year ||
			(year == rhs.year && month < rhs.month) ||
			(year == rhs.year && month == rhs.month && day < rhs.day);
	}
	bool operator>(Date& rhs)
	{
		return year > rhs.year ||
			(year == rhs.year && month > rhs.month) ||
			(year == rhs.year && month == rhs.month && day > rhs.day);
	}

이런 식으로 해주면 되는데요. 작고 큰 것에 대한 날짜의 오버로딩을 해주기 위해서 이런 식으로 해주면 됩니다. 

 

bool operator==(Date& rhs) {
	return year == rhs.year && month == rhs.month && day == rhs.day;
}
bool operator!=(Date& rhs) {
	return !(*this == rhs);
}

이런 식으로 ==이 있다면 !=도 구현을 해주셔야 합니다. !=은 간단하게 되기 때문에 불편하더라도 만들어주시는 것이 좋습니다. ==을 해서 뒤집기만 하는 방식을 위임이라고 합니다. !(*this == rhs) 에서 == 를 불러와서 뒤집어준 것 뿐이기 때문에 이것을 delegation이라고 부릅니다.

 

Date& operator++() {
	if (last_day_of_year()) {
		year++, month = 1, day = 1;
	}
	else if (last_day_of_month()) {
		month++; day = 1;
	}
	else {
		day++;
	}
	return *this;
}

이건 증감연사자(++,--) 같은 경우 자신을 반환해야 합니다. 왜냐하면 종종 증감연산자의 반환결과를 다른 연산에 즉시 이용하기 때문입니다. 전위 증감 연산자가 참조를 반환하는 이유는 객체를 복사할 필요가 없거나 혹은 복사되어서는 안되기 때문입니다. 

 

++(++s); 만약 이런 경우 s는 2만큼 증가합니다. 만약 참조에 의한 반환이 아니었다면 s는 1만큼 증가하고, s의 복사본이 다시 증가하므로 결과적으로 s는 1에 증가하는데 그칩니다. 

 

Date operator++(int) {
	Date ret = *this;

	if (last_day_of_year()) {
		year++, month = 1, day = 1;
	}
	else if (last_day_of_month()) {
		month++; day = 1;
	}
	else {
		day++;
	}
	return ret;
}

후위연산자는 & 참조의 필요가 없습니다. 객체를 복사할 필요가 없는 것이 ret이 지역변수이기 때문에 해도 소용이 없고 s가 2가 증가할 것이라는 기대도 없기 때문에 연산 적용 이전의 상태를 반환해야 하므로 참조가 필요없는 것입니다.