11. 클래스의 활용
이 챕터는 C++ 클래스의 활용과 특징에 대해 설명한다. 클래스는 강력하고 복잡하지만, 객체를 정의하고, 생성자와 소멸자를 통해 객체의 생성과 파괴를 관리하는 방법을 배운다. 또한, 자동 데이터형 변환, 데이터형 캐스트, 클래스 변환 함수 등의 개념을 소개하며, 참조 매개변수와 일반 매개변수 차이, 파괴자를 생략했을 때의 영향을 실험하면서 학습을 권장한다. 실수를 통해 에러를 해결하는 과정에서 C++의 동작 원리를 깊이 이해하게 될 것이라고 강조한다
연산자 오버로딩
C++에서 연산자 오버로딩을 사용하면 사용자 정의 데이터형에 연산자를 적용할 수 있다. 예를 들어, 시간(Time) 객체에서 더하기 연산을 수행할 때, 일반적인 함수 호출 대신 + 연산자를 통해 쉽게 더할 수 있다. 이를 통해 코드의 가독성을 높이고, 보다 직관적인 프로그래밍을 할 수 있다.
다음은 Time 클래스를 정의하고, 연산자 오버로딩을 적용하는 예제 코드이다.
1. Time 클래스 정의 (mytimeO.h)
#ifndef MYTIMEO_H
#define MYTIMEO_H
class Time {
private:
int hours;
int minutes;
public:
Time(); // 기본 생성자
Time(int h, int m = 0); // 매개변수 있는 생성자
void AddMin(int m); // 분 더하기
void AddHr(int h); // 시간 더하기
void Reset(int h = 0, int m = 0); // 시간 재설정
Time Sum(const Time & t) const; // 두 Time 객체의 합을 반환
void Show() const; // 시간 출력
};
#endif
2. Time 클래스의 구현 (mytimeO.cpp)
#include <iostream>
#include "mytimeO.h"
Time::Time() {
hours = minutes = 0;
}
Time::Time(int h, int m) {
hours = h;
minutes = m;
}
void Time::AddMin(int m) {
minutes += m;
hours += minutes / 60;
minutes %= 60;
}
void Time::AddHr(int h) {
hours += h;
}
void Time::Reset(int h, int m) {
hours = h;
minutes = m;
}
Time Time::Sum(const Time & t) const {
Time sum;
sum.minutes = minutes + t.minutes;
sum.hours = hours + t.hours + sum.minutes / 60;
sum.minutes %= 60;
return sum;
}
void Time::Show() const {
std::cout << hours << "시간, " << minutes << "분";
}
3. Time 클래스를 사용하는 프로그램 (usetimeO.cpp)
#include <iostream>
#include "mytimeO.h"
int main() {
using std::cout;
using std::endl;
Time planning;
Time coding(2, 40);
Time fixing(5, 55);
Time total;
cout << "planning time = ";
planning.Show();
cout << endl;
cout << "coding time = ";
coding.Show();
cout << endl;
cout << "fixing time = ";
fixing.Show();
cout << endl;
total = coding.Sum(fixing); // Sum 메서드를 사용해 두 시간을 더한다.
cout << "coding.Sum(fixing) = ";
total.Show();
cout << endl;
return 0;
}
4. 프로그램 출력 결과:
planning time = 0시간, 0분
coding time = 2시간, 40분
fixing time = 5시간, 55분
coding.Sum(fixing) = 8시간, 35분
연산자 오버로딩(operator overloading)은 C++에서 기존의 연산자들(예: +, -, *, ==)을 사용자 정의 데이터형에 대해 재정의하여 사용할 수 있게 하는 기능이다. 즉, 연산자 오버로딩을 통해 클래스나 구조체 같은 사용자 정의 타입에서 연산자들이 적절한 방식으로 작동하도록 정의할 수 있다.
연산자 오버로딩의 기본 개념
C++에서는 내장 타입(int, float, double 등)에 대해 다양한 연산자를 제공한다. 예를 들어, + 연산자는 두 개의 정수를 더하거나, 두 개의 실수를 더하는 데 사용된다. 연산자 오버로딩을 통해 이러한 연산자를 사용자 정의 데이터형에서도 사용할 수 있다.
연산자 오버로딩의 형식
연산자 오버로딩은 함수로 구현되며, operator 키워드 뒤에 연산자를 붙여서 함수처럼 정의한다. 연산자의 좌항 또는 우항에 있는 피연산자를 처리하는 방식으로 정의할 수 있으며, 클래스의 멤버 함수나 외부 함수로 구현할 수 있다.
예시: + 연산자의 오버로딩
다음은 두 개의 Complex 객체를 더하는 + 연산자를 오버로딩한 예제다.
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// + 연산자 오버로딩
Complex operator+(const Complex& other) {
return Complex(real + other.real, imag + other.imag);
}
void display() const {
std::cout << "(" << real << " + " << imag << "i)" << std::endl;
}
};
int main() {
Complex num1(1.0, 2.0);
Complex num2(2.5, 3.5);
Complex sum = num1 + num2; // + 연산자 오버로딩을 사용
sum.display(); // (3.5 + 5.5i)
return 0;
}
이 예제에서 + 연산자를 오버로딩하여 두 개의 Complex 객체를 더할 수 있다. operator+() 함수는 좌항 객체(즉, num1)와 우항 객체(즉, num2)의 실수와 허수를 각각 더한 후 새로운 Complex 객체를 반환한다.
연산자 오버로딩의 규칙
새로운 연산자는 정의할 수 없다. C++에서 이미 존재하는 연산자만 오버로딩할 수 있으며, 새로운 기호를 연산자로 정의할 수 없다.
연산자의 기본 의미를 변경할 수 없다. 예를 들어, = 연산자는 대입을 의미하며, 이 의미를 완전히 변경할 수는 없다. 다만, 대입 연산자가 객체에서 작동하는 방식을 변경할 수는 있다.
연산자의 우선순위는 변경할 수 없다. 오버로딩해도 기존의 우선순위와 결합 규칙은 그대로 유지된다.
연산자의 기본 피연산자 수를 변경할 수 없다. 예를 들어, +는 이항 연산자이므로 두 개의 피연산자를 받아야 한다.
멤버 함수와 비멤버 함수로 오버로딩
멤버 함수로 오버로딩: 연산자의 좌항이 항상 해당 클래스의 객체여야 한다.
비멤버 함수로 오버로딩: 두 피연산자가 모두 클래스 외부에서 제공되는 경우 사용된다.
연산자 오버로딩의 장점
코드 가독성 향상: 연산자 오버로딩을 통해 객체 간의 연산을 직관적으로 표현할 수 있어 코드 가독성이 높아진다.
유연한 연산 처리: 사용자 정의 데이터형에서 다양한 연산을 처리할 수 있도록 확장 가능하다.
객체 지향적 접근: 객체 간의 연산을 함수 대신 연산자로 표현함으로써 더 객체 지향적인 코드를 작성할 수 있다.
예시: == 연산자 오버로딩
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// == 연산자 오버로딩
bool operator==(const Complex& other) const {
return (real == other.real) && (imag == other.imag);
}
};
int main() {
Complex num1(3.0, 4.0);
Complex num2(3.0, 4.0);
if (num1 == num2) {
std::cout << "두 복소수는 같다." << std::endl;
}
return 0;
}
이 예제에서는 == 연산자를 오버로딩하여 두 Complex 객체의 실수와 허수가 모두 같은지 비교할 수 있다.
결론
연산자 오버로딩은 C++에서 객체를 다루는 방식을 더욱 자연스럽고 직관적으로 만들어주는 중요한 기능이다. 이를 통해 클래스 객체가 내장형 데이터처럼 쉽게 연산될 수 있으며, 코드의 가독성과 유지 보수성을 향상시킬 수 있다.
'스터디 > C++ 스터디' 카테고리의 다른 글
C++ 챕터 13장 기초정리 (0) | 2024.09.28 |
---|---|
C++ 챕터 12장 기초정리 (0) | 2024.09.28 |
C++ 챕터 10장 기초정리 (0) | 2024.09.25 |
C++ 챕터 1~ 9장 기초 정리 (0) | 2024.09.24 |