- 연산자 오버로딩: operator_overloading.md
- 포인터와 레퍼런스의 차이: pointer_and_reference.md
- const 멤버 함수: const_member_function.md
- 참고문헌: references.md
-
-
Save onmoving/4631169 to your computer and use it in GitHub Desktop.
#const 멤버 함수
클래스의 멤버 함수를 const로 지정하면 함수 내에서 멤버 변수를 변경하지 않는 것을 컴파일 단계에서 체크할 수 있다.
class Point
{
int x;
int y;
public:
Point(int _x =0 , int _y = 0 ):x(_x),y(_y) { }
void Print( ) const // const 함수
{
cout << x <<',' << y << endl;
}
int getX() const // const 함수
{
return x;
}
int getY() const // const 함수
{
return y;
}
void setX(int _x)
{
x = _x;
}
void setY(int _y)
{
y = _y
}
};
void main( )
{
const Point p1(2,3)
Point p2(5,5);
p1.Print();
p2.Print();
p1.setX(10); // compile error: p1은 const 객체임
p1.setY(10); // compile error: p1은 const 객체임
p2.setX(10); // OK
p2.setY(10); // OK
cout << "p1: " << p1.getX() << ", " << p1.getY() << endl;
cout << "p2: " << p2.getX() << ", " << p2.getY() << endl;
}
#연산자 오버로딩
##연산자 오버로딩의 방법 2 가지
연자자를 오버로딩하는 방법은 2가지로 첫째로 클래스의 멤버함수로 구현하는 방법과 둘째로 전역함수로 구현하는 방법이 있다.
Point p1(0,1), p2(2, 3);
if(p1 == p2) {
...
}
위 코드에서 p1 == p2
를 컴파일러에서 아래 두 가지로 해석할 수 있다.
p1.operator == (p2)
: 연산자가 멤버함수로 구현된 것으로 해석operator == (p1, p2)
: 연사자가 전역함수로 구현된 것으로 해석
두 가지 방법 중 멤버함수로 구현이 가능하다면 멤버함수 방법을 사용하고, 멤버함수 방법이 불가능한 경우에는 전역함수 방법을 사용하도록 한다.
멤버함수로 해석이 불가능한 경우는 첫번째 피연산자인 p1이 Point 객체가 아닌 다른 타입인 경우이다. 이 경우에는 전역함수 구현으로 해석이 된다.
int x = 10
if(x == p2) {
...
}
위 코드에서는 x가 Point 형식이 아니므로 operator == (x, p2)로 해석된다.
##++연산자
전위 ++, 후위 ++의 구분
Point p1(0, 1), p2(2, 3)
++p1; // p1.operator++()로 해석
p2++; // p2.operator++(0)로 해석
후위 ++인 경우 더비 인자로 0을 전달하는 것을 기억하자.
코드 예제
class Point
{
int x;
int y;
public:
Point(int _x =0 , int _y =0 ):x(_x),y(_y) { }
void Print( )const { cout << x <<',' << y << endl; }
const Point& operator++ ( ) // 전위 ++
{
x++;
y++;
return *this;
}
const Point operator++(int ) // 후위 ++
{
Point pt(x, y);
++x;
++y;
return pt;
}
};
void main( )
{
Point p1(2,3), p2(2,3);
Point result;
result = ++p1; // p1.operator++(); 와 같습니다.
p1.Print();
result.Print();
result = p2++; // p2.operator++(0); 와 같습니다.
p2.Print();
result.Print();
}
위 코드 예제에서 전위연산자인 경우 this 객체를 반환하는 데 반해 후위 연산자는 새로운 Point 객체를 반환했다. 반드시 그래야 하는 것은 아니지만 프로그램의 문맥에 맞게 작성해야 함을 유의하자.
#레퍼런스 변수
##포인터와 레퍼런스의 차이
###각가의 정의
- 포인터: 메모리의 주소를 가지는 값. 즉 어떤 대상을 가리키는 값이다.
- 레퍼런스: 메모리를 차지하고 있는 어떤 인스턴스에 대한 별칭. 즉 어떤 대상을 지칭하는 또하나의 이름이다.
###포인터는 아무 것도 가리키지 않을 수 있다. 레퍼런스는 아무 것도 아닌 것에 대한 별칭이 있을 수 없다
즉 포인터는 NULL 포인터라는 것이 존재한다. 하지만 NULL 레퍼런스는 말이 안된다. 이는 코딩 시 중요한 차이점이 있는데
Point *ppt; // 오류 없음
Point &rpt; // 오류
ppt는 초기화 하지 않고 코드를 작성하는 것이 가능하지만 rpt는 무엇에 대한 레퍼런스 인지 명시 해야 한다. 클래스인 경우에는 레퍼런스의 초기화는 생성자에서 할 수 있다.
###포인터의 값은 변경이 가능하지만 레퍼런스는 변경이 불가능하다
###레퍼런스 사용에 대한 지침
- 만들어 지지 않을 수도 있는 객체를 사용한다면 포인터를 사용한다.
- 값이 변할 수 있는 변수를 사용한다면 포인터를 사용한다.
- 반드시 있는 객체를 다룬다면 레퍼런스를 사용한다.
- 객체의 생성과 소멸 시기를 명확히 알 지 못한다면 포인터를 사용한다.
###레퍼런스의 사용 예
- 연산자의 오버로딩 파라미터 객체의 변수를 레퍼런스로 사용하는 경우 가 많다.
코드예
const Point operator+(const Point& arg) const
{
Point pt;
pt.x = this-> x + arg.x;
pt.y = this-> y + arg.y;
return pt;
}
#참고문험
- 뇌를 자극하는 C++ STL(공동환), 한빛미디어: 예제 코드의 많은 부분을 참고하여 수정하거나, 그대로 발췌하였습니다.
- 이펙티브 C++(스캇 마이어스)
- 1장: 포인터와 레퍼런스