sum = x + y + z 이것을 구현하자.
멤버 함수로 구현.
비멤버 함수(프랜드 함수)로 구현 // 인자 갯수의 차이가 난다.
원점 벡터 예제
private:
double x, y;
public:
Vector(double x, int double){
this->x = x;
this->y = y;
}
반환형 operator연산자(매개 변수 목록)
{
....// 연산 수행
}
(예) Vector operator+(const Vector&, const Vector&); // 반환값이 클래스.
// 공개된 멤버만 접근이 불가해서, 프렌드로 구현하는게 좋다.
실질적인 예를 살펴보자
비멤버 함수(레퍼런스)로 구현.
class Vector
{
private:
double x, y;
public:
Vector(double x, double y){
this->x = x;
this->y = y;
}
void display()
{
cout << "(" << x << ", " << y << ")" << endl;
}
friend Vector operator+(const Vector& v1, const Vector& v2); // 순서가 중요하다. // 외부정의
};
Vector operator+(const Vector& v1, const Vector& v2)
{
Vector v(0.0, 0.0); // 임시객채를 생성해서
v.x = v1.x + v2.x;
v.y = v1.y + v2.y;
return v; // 반환
}
- > 이것을 간결하게
return Verctor(v1.x + v2.x , v1.y + v2.y); // 이름없는 객채를 반환해도 가능.
int main()
{
Vector v1(1, 2), v2(3, 4);
Vector v3 = v1 + v2; // 반환된 객채를 불러온후 그 다음에 v3에 정의를 한다.
// 복사 생성자는 2번 호출된다, 반환될때, 그리고 v3를 정의할때.
v3.display();
return 0;
}
멤버 함수로 구현
class Vector
{
private:
double x, y;
public:
Vector(double x, double y){
this->x = x;
this->y = y;
}
Vector operator+(Vector& v2)
{
Vector v(0.0, 0.0);
v.x = this->x + v2.x;
v.y = this->y + v2.y;
return v;
}
void display()
{
cout << "(" << x << ", " << y << ")" << endl;
}
};
int main()
{
Vector v1(1.0, 2.0), v2(3.0, 4.0);
Vector v3 = v1 + v2;
v3.display();
return 0;
}
-> 프로토 타입을 어떻게???? 시험
Vector& operator= (const Vector& v2) // 이것은 얕은 복사이다.
{
this->x = v2.x;
this->y = v2.y;
return *this; // 레퍼런스를 반환한다, 자신을 반환해야지 연속적으로 사용가능하다.
} - > 디폴트로 프로그램에서 만들어 준다.
레퍼런스를 반환하는 이유??
- 연쇄적으로 호출하도록
v1 = v2 = v3 - > v2= v3 -> 레퍼런스로 리턴 - > v1 = v2
- 만약 값으로 반환된다면 다음으로 반환되지 않는다.
cout<< v1 << v2 << v3; //연쇄적으로
-> v1 호출후 반환되는 값은? cout 이 되야지 v2 호출, v3 호출이 가능하다.
깊은 복사를 예제로 살펴보면
class MyArray {
friend ostream& operator<<(ostream &, const MyArray &); // 출력 연산자 <<
private:
int *data; // 배열의 데이터
int size; // 배열의 크기
public:
MyArray(int size = 10); // 디폴트 생성자
~MyArray(); // 소멸자
int getSize() const; // 배열의 크기를 반환
MyArray& operator=(const MyArray &a); // = 연산자 중복 정의
int& operator[](int i); // [] 연산자 중복: 설정자
};
MyArray::MyArray(int s) {
size = (s > 0 ? s : 10); // 디폴트 크기를 10으로 한다.
data = new int[size]; // 동적 메모리 할당
for (int i = 0; i < size; i++)
data[i] = 0; // 요소들의 초기화
}
MyArray::~MyArray() {
delete [] data; // 동적 메모리 반납
data = NULL;
}
MyArray& MyArray::operator=(const MyArray& a) {
if (&a != this) { // 자기 자신인지를 체크
delete [] data; // 기존의 데이터를 동적 메모리 반납
size = a.size; // 새로운 크기를 설정
data = new int[size]; // 새로운 동적 메모리 할당
for (int i = 0; i < size; i++)
data[i] = a.data[i]; // 데이터 복사
}
return *this; // a = b = c와 같은 경우를 대비
} // 자신이면, 그냥 자신을 반환한다.
int MyArray::getSize() const
{
return size;
}
int& MyArray::operator[](int index) {
assert(0 <= index && index < size); // 인데스가 범위에 있지 않으면 중지
return data[index];
}
// 프렌드 함수 정의
ostream& operator<<(ostream &output, const MyArray &a) {
int i;
for (i = 0; i < a.size; i++) {
output << a.data[i] << ' ';
}
output << endl;
return output; // cout << a1 << a2 << a3와 같은 경우 대비
}
int main()
{
MyArray a1(10);
a1[0] = 1;
a1[1] = 2;
a1[2] = 3;
a1[3] = 4;
cout << a1 ;
return 0;
}
-> 자신을 참고할때는 예외
클래스 빅3 : 동적할당데이터를 가질경우
- 소멸자 : 동적할당 해제
- 복사 생성자 : 깊은 복사(초기화) - 한번만 가짐
- = 연산자 함수 : 깊은 복사(대입) - 만들어진후 계속 값이 바뀜
== 연산자 중복
- 반환값은 bool 타입이 되야한다.
// 프렌드 함수로 정의
bool operator==(const Vector &v1, const Vector &v2)
{
return v1.x == v2.x && v2.y == v2.y;
}
// 프렌드 함수로 정의
bool operator!=(const Vector &v1, const Vector &v2)
{
return !(v1 == v2); // 오버로딩된 == 연산자를 이용
}
<<과 >> 연산자 중복
cout<< 3 << 3.14 << 'a'<< "hello";
cout<< v; = >
class Vector
{
private:
double x, y;
public:
Vector(double x, double y){
this->x = x;
this->y = y;
}
Vector operator+(const Vector& v2) const
{
Vector v(0.0, 0.0);
v.x = this->x + v2.x;
v.y = this->y + v2.y;
return v;
}
friend ostream& operator<<(ostream& os, const Vector& v);
};
ostream& operator<<(ostream& os, const Vector& v)
{
os << "(" << v.x << "," << v.y << ")" << endl;
return os;
}
int main()
{
Vector v1(1.0, 2.0), v2(3.0, 4.0);
Vector v3 = v1 + v2;
cout << v1 << v2 << v3;
return 0;
}
연산자 중복시 주의할 점
- 새로운 연산자를 만드는 것은 허용되지 않는다.
- :: 연산자, .* 연산자, . 연산자, ?: 연산자는 중복이 불가능하다. // :: 클래스 멤버, . 멤버 변수에, ? 삼항연산자 중복 불가
- 내장된 int형이나 double형에 대한 연산자의 의미를 변경할 수는 없다.
- int operator+ (int a, int b)
{return a + b + 1 } // 이것이 불가능하다, +1하면 심각한 문제. - 연산자들의 우선 순위나 결합 법칙은 변경되지 않는다.
- 만약 + 연산자를 오버로딩하였다면 일관성을 위하여 +=, -= 연산자도 오버로딩하는 것이 좋다.
- 일반적으로 산술 연산자와 관계 연산자는 비멤버 함수로 정의한다. 반면에 할당 연산자는 멤버 함수로 정의한다.
1. 벡터를 나타내는 Vector 클래스에 - 연산자를 중복하라.
2. 벡터를 나타내는 Vector 클래스에 += 연산자를 중복하라.
3. 문자열을 나타내는 String 클래스를 작성하고 << 연산자를 중복하라.
타입 변환
생성자 중복정의
- 기본 생성자
- 복사 생성자
- 반환생성자
- 다중인자 생성자
변환 생성자
class Book
{
private:
int isbn; // 책의 ISBN
string title; // 책의 제목
public:
Book() { // 생성자
isbn = 0;
title = “unknown";
}
Book(int isbn) // 다른 타입이라서 변환 생성자.
this->isbn = isbn;
this->title = "unknown";
}
void display() {
cout << isbn << ":" << title << endl;
}
};
int main()
{
Book b1 = 9782001; // int 타입을 Book 타입에 대입
// 정수형을 객체에 대입한 것 처럼, 그래서 변환 생성자
b1.display();
b1 = 9783001; // 가능
b1.display();
return 0;
}
#include <iostream>
#include <string>
using namespace std;
class Book
{
private:
int isbn;
string title;
public:
Book(int isbn, string& title) {
this->isbn = isbn;
this->title = title;
}
Book(int isbn) {
this->isbn = isbn;
this->title = "unknown";
}
operator int() const
{
return isbn;
}
void display() {
cout << isbn << ":" << title << endl;
}
};
bool check(int isbn)
{
cout << isbn << endl;
return true;
}
int main()
{
Book b1 = 9782001; // 변환 생성자 실행!
b1.display();
int isbn = b1; // 변환 연산자 실행!
cout << isbn << endl;
check(b1); // 변환 연산자 실행!
return 0;
}