스터디/C++

연산자 다중정의

elenalee 2023. 10. 17. 10:56

1. 연산자 다중정의

 

피연산자의 자료형과 연산자

연산자는 피연산자의 자료형에 따라 적절한 처리절차가 정의되어 있음

동일 연산자라도 자료형에 따라 구체적인 처리방법 상이

 

(1) 연산자 다중정의 

c++에 정의된 연산자를 사용자가 선언한 클래스 객체에 대해 사용할수 있도록 정의

 

** 주의사항

연산자의 의미를 임의로 바꾸지 않음, 연산자의 고유한 특성 유지

(우선순위, 피연산자의 수, 전위 표기와 후위표기 연산자의 의미 유지)

 

** 다중정의 대상 주요 연산자 

▷ 클래스 객체간 대입 및 이동대입 연산자  : 동적 할당을 받는 포인터를 포함하는 경우 등

▷ 수치형 객체의 산술연산자 다중정의 : 교환법칙 고려

객체를 비교하기 위한 관계 연산자의 다중정의

스트림 입력 및 출력을 위한 >>, << 연산자 

 

** 다중정의 불가 연산자

멤버 선택 연산자(.) ex) a.x 

멤버에 대한 포인터 연산자 (.*)

유효범위 결정 연산자 (::)

조건 연산자(? :)

 

** 다중정의 위치

▷ 클래스의 멤버로 정의 : 연산자 구현과정에서 객체의 멤버를 엑세스 할수 있음 

▷ 클래스 외부에서 정의 : 객체의 private멤버 직접 사용불가 (private멤버 엑세스 별도 구성)

 

 

 

(2) 단항 연산자의 다중정의

피연산자가 1개, 전위표기법과 후위표기법 

 

단항연산자의 다중정의 (클래스내 정의)

전위표기법은 객체의 참조를 반환하며, 후위표기법은 클래스의 객체를 반환 

 

ex) Pencils 클래스 

① n타스 m자루 연칠의 갯수를 표현하는 class선언, ② 낱개의 수를 1개 증가시키는 전위, 표위표기 ++ 연산자 포함, ③ 연필의 수량을 출력하는 멤버함수 포함

 

** 행위 (멤버 함수)

 

** 속성 (데이터 멤버: 메모리 할당을 받아야 하며, 할당된 메모리를 연결하는 포인터) 

 

 

 

(3) 이항 연산자의 다중정의

 

이항연산자 정의 

opSymbol: +, -, *, / , &&, || 등의 이항 연산자 기호

객체 자신이 좌측 피연산자, args가 우측 피연산자에 해당됨 

a(객체 자신) + b(args)

 

 

 

 

(4) 스트림 출력 연산자(<<) 다중정의

 

▷ 스트림 출력 연산자를 정의할 위치 

좌측 피연산자인 cout은 Complex2의 객체가 아니며, cout이 속한 ostram클래스를 일반 프로그래머 수정불가

 클래스에 속하지 않는 외부 별도 연산자로 정의, << 연산자가 Complex2객체의 private멤버를 엑세스 할수 있도록 friend로 지정 

 

▷ 스트림 출력 연산자를 정의(위치) 

 

 

2. 대입 및 이동대입 연산자

(1) 대입연산자 (=)

묵시적인 대입연산자 : 우측 피연산자의 데이터 멤버를 좌측 피연산자에 복사

- 객체에 동적 할당된 메모리 포인터가 포함된 경우 의도하지 않은 공유 상태의 문제야기

- 깊은 복사를 할수 있는 대입 연산자를 다중정의할 필요가 있음 

 

 

(2) 이동대입연산자 (=)

좌측 피연산자에 대입할 우측 피연산자가 rvalue일때 사용

- 대입후 우측 피연산자 불필요 (rvalue의 자원을 이동하게 함)

- 우측 피연산자의 내용을 좌측 피연산자로 이동, 불필요한 복사없어 효율성 증대

 

(3) 대입 및 이동 대입연산자 활용 

 

(4) std::move 함수의 활용

 

두 VecF객체를 교환하는 함수의 구현 (swap )

 

 인수로 전달되는 객체의 rvalue 참조를 반환 

VecF tmp = std::move(v1)   v1의 rvalue의 참조를 구하여 tmp의 초기화에 사용 (이동 생성자로 tmp생성)

v1 = std::move(v2)  v2의 rvalue 참조를 구하여 v1에 대입 (이동대입 연산자 실행)

 

(5) []연산자의 다중정의 

 

SafeIntArray 클래스 

① 배열처럼 지정된 개수의 int값 저장 ex) SafeIntArray a(10), ② 각각의 값들은 0부터 일련번호를 첨자로 지정하여 엑세스 ex) a[5]=10 (6번째 위치에 10저장), ③ 첨자가 지정된 범위를 벗어날 경우 오류메시지 출력하고 프로그램 종료  ex) cout << a[11]

 

[]연산자 

- 배열의 첨자를 지정하는 이항 연산자(피연산자 2개), 피연산자: 배열첨자

- 데이터를 저장하기 위해 사용할 []연산자,  SafeIntArray a(10), a[5]=10

 

const 객체를 위한 []연산자 (데이터를 읽기만 할수 있도록 const를 적용한 []연산자 정의)

 

3. C 스타일 문자열 

 

(1) 문자열 ( Null-terminated string )

- 일반 문자열: 문자열의 크기대로 공간확보, 문자열의 끝에 null문자 ('\0')사용 

- 배열이 크기가 명시되지 않으면 배열의 크기 + 1 

- 문자열 리터럴 : 메모리에 공간이 만들어지고, 포인터 표시

 

(2) C스타일 문자열 처리함수

- 헤더파일: #include <cstring>

 

▷ 문자열 길이 : strlen(포인터), null포인터 미반영

     size_t strlen(const char* str);       ex) n= strlen("abcde") → n = 5

 

 

▷ 문자열 복사 : strcpy(목적지 포인터, 소스포인터)

    char* strcpy(char* strDestination, const char* strSource) 

문자열 copy와 '\0' 생성으로 이후 문자열은 (있어도) 없는 것으로 간주

 

▷ 문자열 연결 : strcat(목적지 포인터, 소스포인터)

    char* strcat(char* strDestination, const char* strSource) 

 

(3) 새로운 C 문자열 스타일 생성 연습

 

** 요구사항 

-문자열을 저장하되 다중정의된 연산자를 포함하며 실행시 필요에 따라 저장공간을 늘릴수 있음

( char s1[10]; char s2[10]; s1 ="abc" 혹은 s1=s2 오류, s1/s2는 배열의 포인터이므로 복사불가 )

 

 

(4) String

- 문자열을 저장하기 위한 c++ 표준 라이브러리 클래스   

   basic_string<char> (문자를 저장하기 위한 c++의 기본클래스)

- 헤더파일 #include <string>

- 연산자 : [], +, =, +=, ==, !==, >, >=, < , <=, 스트림 입출력(<<, >>)등

- 멤버함수: length, append, find, c_str (cstyle문자열 변환)등

- 함수: stoi, stod, to_string, swap, getline 등 (string을 int, double, 객체변환 등)

 

 

4. 자료형 변환

(1) 묵시적 형변환 

MyString클래스의 묵시적 형변환

str3 = "Programming";  c스타일 문자열을 MyString객체에 대입하기 위해 컴파일러가 생성자를 참조 MyString으로 묵시적 형변환 

MyString에 대한 rvalue이므로 이동대입연산 적용/대입

 

(2) 형변환 연산자를 정의하는 위치 

 

값을 제공하는 송신측 클래스에서 정의 (값을 받는 수신측 클래스 이름으로 연산자 정의)

    ex) MyString클래스의 객체를 C스타일 문자열로 변환 (자신은 const로 유지하면서 형변환만 진행)

'operator 자료형 이름'형식

 값을 제공받는 수신측 클래스에서 정의 (송신측 클래스의 객체를 인수로 받는 1인수 생성자 정의)

    ex) MyString(const char* str); 

    ** 송신측 클래스의 private멤버를 엑세스해야하면, 변환대상 송신클래스애서 private멤버 엑세스가능한 조치필요

private데이터 멤버를 사용할수 있도록 조치 (friend방법도 있음)

 

(3) 생성자를 이용한 묵시적 형변환 금지

-  explicit으로 선언된 생성자 

-  명시적 형변환을 지정시에는 생성자를 직접 호출하거나 형변환 연산자(static cast)활용