티스토리 뷰
람다함수호출 과련 기본지식
1. 연산자 오버로딩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 |
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point
{
int x, y;
public:
Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
void Print() { cout << x << ", " << y << endl; }
Point operator+(Point& arg)
{
Point pt;
pt.x = this->x + arg.x; // p1.x + arg.x
pt.y = this->y + arg.y;
return pt;
}
};
int main()
{
Point p1(2, 3), p2(5, 5);
Point p3 = p1.operator+(p2);
p3.Print();
p3 = p1 + p2; // p1.operator+(p2) 처럼 살행됨
p3.Print();
_gettch();
return 0;
} |
cs |
<실행>
2. 함수호출 연산자 오버로딩 - ()연산자
객체를 함수처럼 동작하게 한다.
27행 Print3는 함수 호출하는것이 아닌 객체로 ()연산자를 이용해서 마치 함수가 호출하는것 처럼 사용된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 |
#include "stdafx.h"
#include <iostream>
using namespace std;
struct FuncObject
{
public:
void operator()(int arg)
{
cout << "정수 : " << arg << endl;
}
};
void Print1(int arg)
{
cout << "함수호출, 정수 : " << arg << endl;
}
int main()
{
void (*Print2)(int) = Print1; // 함수포인터
FuncObject Print3;
Print1(11);
Print2(22);
Print3.operator()(33);
Print3(44); // Print3.operator()(44) 과 같음, 객체를 함수처럼 동작하게 하는 연산자
_gettch();
return 0;
} |
cs |
<실행>
3. 배열 인덱스 연산자 오버로딩 - []연산자 오버로딩
많은 객체를 저장하고 관리하는 객체에 사용
일반적으로, 컨테이너 객체에 사용하여 컨테이너 객체가 관리하는 내부 원소에 접근할때 사용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 |
#include "stdafx.h"
#include <iostream>
using namespace std;
class Array {
int *arr, size, capacity;
public:
Array(int cap = 100) : arr(0), size(0), capacity(cap) {
arr = new int[capacity];
}
~Array() {
delete[] arr;
}
void Add(int data) {
if (size < capacity)
arr[size++] = data;
}
int Size() {
return size;
}
int operator[] (int idx) {
return arr[idx];
}
};
int main()
{
Array ar(10);
ar.Add(10), ar.Add(20), ar.Add(30);
for (int i = 0; i < ar.Size(); i++)
cout << ar[i] << endl; // ar[i] 는 일반 배열이 아닌 객체의 []연산자 이다
_gettch();
return 0;
} |
cs |
<실행>
4. 메모리 접그, 클래스 멤버 접근 연산자 오버로딩 - *, -> 연산자
스마트포인터는 메모리 접근, 클래스 멤버 접근 기본 기능외에 메모리 해제를 자동으로 해준다.
아래 코드에서는 프로그램 실행 중에 함수가 종료되거나 에외 등이 발생하는 경우 delete p1, p2 가 실행되지 않아 메모리 누수가 발생할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
class Point {
int x, y;
public:
Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
void Print() { cout << x << ", " << y << endl; }
};
int main()
{
Point *p1 = new Point(2, 3);
Point *p2 = new Point(5, 5);
p1->Print();
p2->Print();
delete p1;
delete p2;
_gettch();
return 0;
} |
cs |
아래 처럼 코드(8~15행)를 추가하면된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 |
class Point {
int x, y;
public:
Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
void Print() { cout << x << ", " << y << endl; }
};
class PointPtr
{
Point *ptr;
public:
PointPtr(Point *p) : ptr(p) {}
~PointPtr() { delete ptr; }
Point* operator->() { return ptr; }
};
int main()
{
PointPtr p1 = new Point(2, 3);
PointPtr p2 = new Point(5, 5);
p1->Print();
p2->Print();
_gettch();
return 0;
} |
cs |
<실행>
*연산자 오버로딩 (15행 추가)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 |
class Point {
int x, y;
public:
Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
void Print() { cout << x << ", " << y << endl; }
};
class PointPtr
{
Point *ptr;
public:
PointPtr(Point *p) : ptr(p) {}
~PointPtr() { delete ptr; }
Point* operator->() { return ptr; }
Point& operator*() { return *ptr; }
};
int main()
{
PointPtr p1 = new Point(2, 3);
PointPtr p2 = new Point(5, 5);
p1->Print();
p2->Print();
(*p1).Print();
(*p2).Print();
_gettch();
return 0;
} |
cs |
<실행>
5. 생성자를 이용한 타입 변환
특정 타입을 인자로 받는 생성자가 있으면 생성자 호출을 통한 타입 변환이 가능하다. (객체 생성 후 대입)
생성자를 이용해 다른 타입을 자신의 타입으로 변환
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 |
class A{};
class B{
public:
B() { cout << "B() 생성자" << endl; }
B(A& _a) { cout << "B(A& _a) 생성자" << endl; }
B(int n) { cout << "B(int n) 생성자" << endl; }
B(double d) { cout << "B(double d) 생성자" << endl; }
};
int main()
{
A a;
int n = 10;
double d = 5.5;
B b;
b = a; // b = B(a) 처럼 호출되어 B객체를 만들어 b 에 대입한다.
b = n; // b = B(n)
b = d; // b = B(d)
_gettch();
return 0;
} |
cs |
<실행>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 |
class Point {
int x, y;
public:
Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
void Print() { cout << x << ", " << y << endl; }
};
int main()
{
Point pt;
pt.Print();
pt = 10; // Point(10, 0) 처럼 생성자 호출한다.
pt.Print();
_gettch();
return 0;
} |
cs |
<실행>
이렇게 하면 프로그램은 실행되지만, 의도치 않게 Point 객체에 정수 값을 대입해도 컴파일이 되어 프로그램 실행 시 원하는 결과가 나오지 않는 문제가 있어, 생성자는 명시적 호출만 가능하다록 explicit 키워드를 사용한다.
4행 Point 앞에 explitcit 키워드를 추가하고 컴파일하면 12행 처럼 객체에 정수를 대입하면 오류가 난다.
(참고, pt = 10 //암시적 호출, pt = Point(10) // 명시적 호출)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 |
class Point {
int x, y;
public:
explicit Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
void Print() { cout << x << ", " << y << endl; }
};
int main()
{
Point pt;
pt.Print();
pt = Point(10); // explicit 키워드 사용하면 pt = 10 은 컴파일 에러 발생함
pt.Print();
_gettch();
return 0;
} |
cs |
<실행>
타입 변환 연산자 오버로딩을 이용한 타입 변환
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 |
class A {};
class B {
public:
operator A() {
cout << "operator A() 호출" << endl;
return A();
}
operator int() {
cout << "operator int() 호출" << endl;
return 10;
}
operator double() {
cout << "operator double() 호출" << endl;
return 5.5;
}
};
int main()
{
A a;
int n;
double d;
B b;
a = b; //b.operator A() 암시적호출
n = b; //b.operator int() 암시적호출
d = b; //b.operator double() 암시적호출
cout << endl;
a = b.operator A(); // 명시적호출
n = b.operator int(); // 명시적호출
d = b.operator double(); // 명시적호출
_gettch();
return 0;
} |
cs |
타입 변환 연산자는 생성자나 소멸자처럼 반환 타입을 지정하지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 |
class Point {
int x, y;
public:
explicit Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
void Print() { cout << x << ", " << y << endl; }
operator int() { return x; }
};
int main()
{
int n = 10;
Point pt(2, 3);
n = pt; //pt.operator int() 암시적호출
cout << n << endl;
_gettch();
return 0;
} |
cs |
<실행>
13행 처럼 정수형에 Point 객체를 대입하는 경우 첫번째 인자 값이 대입된다. (올바른 방법은 아닌듯...)