2011. 6. 1. 22:32ㆍC++
1. 연산자 오버로딩 2가지 방법
operator 키워드 + 연산자 를 붙여서 함수명을 만들경우 해당 연산자를 오버로딩 하게 된다.
ex> Point p1,p2;
Point p3 = p1+p2; => p1.operator+(p2) 가 된다.
=> operator+(p1,p2) 가 된다.
class Point {
// 멤버 함수에 의한 연산자 오버로딩
void operator+(int value);
Point operator+(const Point& p);
// 전역함수 연산자 오버로딩 (friend 키워드 사용)
// friend를 붙이면 해당 전역함수에서 이클래스의 private 변수/함수에 접근 가능하다.
friend Point operator+(const Point&, const Point&)
}
Point operator+(const Point& p1, const Point& p2)
{
Point temp(p1.x+p2.x, p1.y+p2.y);
return temp;
}
2. 단항 연산자 오버로딩
class Point {
Point& operator++(); // 멤버함수, Point& 를 리턴해야 ++(++) 방식이 가능하다.
friend Point& operator--(Point& p); // 전역함수
}
// 전역 함수
Point& operator--(Point& p) {
p.x--;
p.y--;
return p;
}
@ ++(++p) 와 --(--p) 는 어떤경우 인가.
++(++p) => operator++( operator++(p) ) 간된다. 즉 해당 operator 함수는
Point& 레퍼런스를 리턴해야 이렇게 호출이 가능하다.
3. 단항연선자의 선연산과 후연산의 구분
++p : 즉시 증가한후 다음라인으로 넘어간다. p.operator++() : 멤버
p++ : 다음라인에서 증가된다. p.operator++(int); // int 매개변수가 아닌 구분을 위한 약속입니
다.
class Point {
Point& operator++(); // 선증가
Point operator++(int); // 후증가
}
// 선증가
Point& Point::operator++() {
x++;
y++;
return *this; // 증가시킨후 현재 객체 레퍼런스를 리턴한다.
}
// 후증가형식으로 연산자 오버로딩 구현방법
Point Point::operator++(int) {
Point temp(x,y); // 증가전의 객체를 생성한다.
x++;
y++;
/**
로컬 객체이므로 참조값을 넘길수가 없습니다. 그래서 복사해서 넘겨야 합니다.
따라서 Point& 가아닌 Point를 리턴합니다.
*/
return temp; // 증가전의 데이터를 리턴한다.
}
4. 연산자 교환 법칙 해결하기
p + 10 == 10 + p
class Point {
Point operator+(int value);
}
int main(void) {
Point p1;
Point p2 = p1 + 3; ==> p1.operator+(3); 을 호출하게 된다.
Point p3 = 3+p1; ==> 불가능하다. 해결방법은? 전역으로 선언하면 된다.
}
교환법칙을 해결하려면 전역 으로 연산자를 오버로딩 하면 됩니다.
해결 예>
Point operator+(int value, Point& p) {
return p+value; // 이런식으로 변환해준다.
}
5. 임시 객체
임시 객체란 이름이 없는 객체를 말합니다.
int a = 3 + 4; // 메모리로 해석하면 3,4도 메모리에 올라갑니다. 따라서 12bytes가 할당됩니다.
여기서 3,4가 바로 임시 객체 형태이며 다음라인으로 넘어가면 자동으로 메모리에서 해지 됩니다.
- 컴파일러에 의해서 최적화 되어 빠르므로 특정 장소요 사용하면 좋습니다.
객체에는 Point(3,4); 와 같이 사용합니다.즉 이름이 없습니다.
Point Point::operator+(int value) {
// 즉 단순 생성후 리턴형에 복사하기 위해서라면 임시 객체를 사용하는것이 좋다.
return Point(x+value,y+value);
}
6. count, cin 그리고 endl의 비밀
-
/*
HelloWorldReview2.cpp
*/
#include<stdio.h>
namespace mystd //mystd라는 이름공간 시작.
{
char* endl="\n";
class ostream // 클래스 ostream 정의
{
public:
ostream& operator<<(char * str) {
printf("%s", str);
return *this;
}
ostream& operator<<(int i) {
printf("%d", i);
return *this;
}
ostream& operator<<(double i) {
printf("%e", i);
return *this;
}
};
ostream cout; //ostream 객체 생성
} // mystd 이름공간 끝.
using mystd::cout;
using mystd::endl;
int main()
{
cout<<"Hello World"<<endl<<3.14<<endl;
return 0;
}
* 객체 정보를 출력하려면
cout<<p -> cout.operator<<(p); // x 불가능함. 멤버함수로는 불가능함.
// 표준 라이브러리에 선언되어 있지 않기때문에 불가능 합니다.
cout<<p -> operator<<(cout,p); // o 전역함수로 가능함.
// 직접 제작하는것이기 때문에 가능합니다.
ostream& operator<<(ostream& os, const Point& p)
friend ostream& operator<<(ostream& os, const Point& p);
}
ostream& operator<<(ostream& os, const Point& p) {
os<<"["<<p.x<<","<<p.y<<"]"<<endl; // Point 객체 정보 출력
return os;
}
int main(void) {
Point p(1,3);
cout<<p; // operator<<(cout,p) 형태의 전역 오버로딩을 통해 가능하다.
}
7. 인덱스 연산자.
arr[i] => arr.operator[](i);
// int& 같이 참조형 객체를 리턴하는 이유는 arr[0] =10; 같이 해당 배열에 값을 저장할수 있어야
하기 때문이다.
int& Arr:operator[](int i) {
return arr[i];
}
8. 대입 연산자 오버로딩
class Point {
char* name; // 디폴트 오버로딩시 문제 방생
}
Point p1;
Point p2 = p1; // 객체 생성시 이므로 Point p2(p1) 같이 복사생성자가 호출된다.
Point p1;
Point p2;
p2 = p1; // 객체 생성이 아니므로 p2.operator=(p1) 이 되는것이다.
// 디폴트일경우는 멤버대 멤버로 복사를 해줍니다.
// 하지만 디폴트 복사생성자 처럼, 가벼운 복사가 이루어 지게 됩니다. 깊은 복사를 수행하려면
// 반드시 오버로딩 하여 메모리 복사까지 수행해 주어야 합니다.
// 아래와 같이 깊은 대입 연산자 오버로딩이 되도록 해주어야 한다.
Point& Point::operator=(const Point& p) {
delete[] p.name;// 읽어버릴 이름의 메모리를 해제해 주어야 합니다.
// 이름에대한 메모리를 할당한다.
this->name = new char[strlen(p.name)+1];
strcpy(name,p.name);
x = p.x;
y = p.y;
return *this;
}