제 12장. 사용자 정의형으로서의 클래스 2011-1학기 프로그래밍언어및실습 (C++)
학습 목표 클래스를 기본형과 비슷한 방법으로 다룰 수 있게 하는 사용자 정의 형으로써의 기능을 알아본다. 클래스의 객체에 대해서 연산자를 사용할 수 있게 하는 연산자 오버로딩 기능에 대해서 알아본다. 연산자 오버로딩을 구현하기 위한 연산자 함수를 정의하는 방법과 주의 사항을 알아본다. 클래스 형을 특정 데이터 형으로 변환하는 변환 연산자를 구현하고 사용하는 알아본다. C++의 형 변환 연산자에 대해서 알아본다. 2011-1학기 프로그래밍언어및실습 (C++)
연산자 오버로딩 기본형에 대해서 사용하는 연산자의 의미를 확대해서 클래스 형에 대해서도 사용할 수 있도록 만드는 기능 2011-1학기 프로그래밍언어및실습 (C++)
연산자 오버로딩의 필요성 class String { ... public: bool IsEqual(const String& s); // 문자열의 내용이 같으면 true를 리턴하는 함수 }; template <typename T> void f(const T& x, const T& y) { if( x == y ) // T 형의 두 변수의 값을 비교한다. } int main() int a = 10, b = 10; f<int>(a, b); // T가 int 형일 때 템플릿의 인스턴스화 OK String s1("abc"), s2("abc"); f<String>(s1, s2); // T가 String 형일 때 템플릿의 인스턴스화 실패 2011-1학기 프로그래밍언어및실습 (C++)
연산자 함수 "operator 연산자"의 형식으로 정의되는 함수 만일 연산자 함수가 정의 되지 않았으면 클래스의 객체에 대해 연산자를 사용하는 것은 컴파일 에러가 된다. 2011-1학기 프로그래밍언어및실습 (C++)
연산자 함수의 정의 (1) 이항 연산자를 연산자 함수로 정의할 때는 피연산자 중 좌변이 객체가 되고, + 연산자가 operator+라는 멤버 함수가 되고, 나머지 피연산자인 우변은 해당 함수의 인자가 된다. 2011-1학기 프로그래밍언어및실습 (C++)
연산자 함수의 정의 (2) class String { ... public: String operator+(const String& s) const; }; String String::operator+(const String& s) const { char* tmp = new char[Size() + s.Size() + 1]; ::strcpy(tmp, m_str); ::strcat(tmp, s.m_str); String result(tmp); delete [] tmp; return result; } 2011-1학기 프로그래밍언어및실습 (C++)
연산자 함수의 구현 연산자 함수의 구현 클래스의 멤버 함수로 정의하는 방법 멤버 함수가 아닌 전역 함수로 정의하는 방법 이항 연산자 오버로딩 연산자 함수를 클래스의 멤버 함수로 정의하면 피연산자 중 하나가 클래스의 객체가 되므로 연산자 함수의 인자의 개수는 하나가 된다. 연산자 함수를 전역 함수로 정의하면 피연산자가 모두 연산자 함수의 인자가 되므로 연산자 함수는 두 개의 인자를 갖게 된다. 2011-1학기 프로그래밍언어및실습 (C++)
멤버 함수로 정의 (1) 이항 연산자의 경우 피연산자 중 좌변을 객체로 잡으면, 연산자가 객체가 속한 클래스의 멤버 함수가 되고, 남은 피연산자가 연산자 함수의 인자가 된다. 연산자 함수를 정의할 때 연산자 함수의 리턴형은 연산의 결과에 따라서 결정된다. 2011-1학기 프로그래밍언어및실습 (C++)
멤버 함수로 정의 (2) class String { ... public: bool operator==(const String& s) const; bool operator!=(const String& s) const; }; bool String::operator==(const String& s) const return ::strcmp(m_str, s.m_str) == 0 ? true : false; } bool String::operator!=(const String& s) const return ::strcmp(m_str, s.m_str) ? true : false; 2011-1학기 프로그래밍언어및실습 (C++)
전역 함수로 정의 (1) 피연산자 중 좌변이 객체가 아니라면 연산자 함수를 전역 함수로 정의한다. 연산자의 피연산자 수와 연산자 함수의 인자의 개수가 항상 같다. 2011-1학기 프로그래밍언어및실습 (C++)
전역 함수로 정의 (2) class String { ... friend String operator+(const char* s1, const String& s2); }; String operator+(const char* s1, const String& s2) char* tmp = new char[::strlen(s1) + s2.Size() + 1]; ::strcpy(tmp, s1); ::strcat(tmp, s2.m_str); String result(tmp); delete[] tmp; return result; } 2011-1학기 프로그래밍언어및실습 (C++)
삽입 연산자 오버로딩 출력에 사용되는 << 연산자를 오버로딩하려면 전역 함수로 정의한다. 2011-1학기 프로그래밍언어및실습 (C++)
연산자 오버로딩의 일반적인 규칙 연산자 오버로딩을 할 때 새로운 연산자를 정의할 수는 없다. 예를 들어 ‘#’을 새로운 연산자로 정의하는 것은 잘못이다. 연산자의 우선 순위, 피연산자의 개수, 결합 방향 등을 변경할 수 없다. 기본형에 대해서는 연산자 오버로딩할 수 없다. 연산자 오버로딩은 반드시 클래스 형에 대해서만 가능하다. 연산자 함수는 반드시 클래스의 멤버 함수 또는 전역 함수로 구현해야 한다. 단항 연산자에 대한 연산자 함수를 멤버 함수로 정의하면 인자 없는 함수로 정의된다. 만일 전역 함수로 정의하면 인자가 하나인 함수로 정의된다. 이항 연산자에 대한 연산자 함수를 멤버 함수로 정의하면 인자가 하나인 함수로 정의된다. 만일 전역 함수로 정의하면 인자가 두 개인 함수로 정의된다. 연산자 함수는 디폴트 인자를 가질 수 없다. 대입 연산자를 제외한 모든 연산자 함수를 상속받을 수 있다. = 연산자, () 연산자, [] 연산자, -> 연산자는 반드시 연산자 함수를 멤버 함수로 정의해야 한다. . 연산자, .* 연산자, :: 연산자, ?: 연산자, # 연산자, ## 연산자는 오버로딩할 수 없다. 2011-1학기 프로그래밍언어및실습 (C++)
클래스 형 변환 특정 데이터 형에서 클래스 형으로의 형 변환은 변환 생성자에 의해서 처리된다. 클래스 형에서 다른 데이터 형으로의 형 변환이 필요할 때는 변환 연산자가 사용된다. 2011-1학기 프로그래밍언어및실습 (C++)
변환 연산자 함수 변환 연산자 함수는 “operator 데이터 형” 형태의 이름을 갖는 함수이다. 리턴형이 없으며, 특별히 void라고 지정하지도 않는다. 항상 인자 없는 함수로 정의된다. 2011-1학기 프로그래밍언어및실습 (C++)
변환 연산자 함수의 예 class String { ... public: operator const char*() const; }; String::operator const char*() const return m_str; } void Test(const char* s) cout << "문자열 : " << (::strlen(s) == 0 ? "없음" : s) << "\n"; int main() String str1; Test(str1); // 변환 연산자 호출 const char* str2 = str1; // 변환 연산자 호출 2011-1학기 프로그래밍언어및실습 (C++)
C++의 형 변환 연산자 C의 형 변환 연산자의 문제점 C++의 형 변환 연산자 형 변환의 의도를 알기가 어렵다. const_cast static_cast dynamic_cast reinterpret_cast 2011-1학기 프로그래밍언어및실습 (C++)
const_cast const 변수에서 const 속성을 제거하기 위한 형 변환에 사용 String s1(“abc”); const String* pStr1 = &s1; pStr1->Set(“def”); // pStr1이 const String* 형이므로 컴파일 에러 String* pStr2 = const_cast<String*>(pStr1); // const 속성을 제거함 pStr2->Set(“def”); // pStr2이 const String* 형이 아니므로 OK 2011-1학기 프로그래밍언어및실습 (C++)
static_cast 컴파일 시 자동 형 변환이 가능한지 검사 형 변환 가능한 경우에는 형 변환을 수행하고 만일 형 변환할 수 없는 경우에는 컴파일 에러를 발생 class Shape { ... }; class Rectangle : public Shape { Rectangle r1; Shape *pShape = static_cast<Shape*>(&r1); // OK; Rectangle *pRect = static_cast<Rectangle*>(pShape); // 컴파일 에러 2011-1학기 프로그래밍언어및실습 (C++)
dynamic_cast 실행 시간에 형 변환 가능하지 검사 만일 형 변환 가능하면 형 변환을 수행하고 형 변환할 수 없는 경우에는 0을 리턴하거나 예외를 발생 Shape* pShape = NULL; int choice; cin >> choice; switch(choice) { case 1 : pShape = new Shape; break; case 2 : pShape = new Rectangle; break; } Rectangle *pRect = dynamic_cast<Rectangle*>(pShape); if( pRect != NULL ) pRect->GetWidth(); 2011-1학기 프로그래밍언어및실습 (C++)
RTTI (1) dynamic_cast 연산자를 사용하려면 C++의 RTTI 기능을 사용해야 한다. RTTI(Run-Time Type Information) 실행 시간에 객체의 클래스 형에 대한 정보를 구할 수 있는 기능 typeid 연산자와 type_info 클래스 제공 Rectangle *pRect = new Rectangle; Shape *pShape = pRect; cout << typeid( pShape ).name() << endl; // class Shape * 출력 cout << typeid( *pShape ).name() << endl; // class Rectangle 출력 cout << typeid( pRect ).name() << endl; // class Rectangle * 출력 cout << typeid( *pRect ).name() << endl; // class Rectangle 출력 delete pRect; 2011-1학기 프로그래밍언어및실습 (C++)
RTTI (2) typeid 연산자 변수나 객체의 형 정보를 저장하는 type_info 클래스 객체의 레퍼런스를 리턴 데이터 형을 비교하는 == 연산자 함수나 != 연산자 함수, 데이터 형 이름을 문자열로 리턴하는 name 함수를 제공 type_info 클래스는 컴파일러에 의해서 내부적으로 정의되며 type_info 클래스의 객체를 생성하는 유일한 방법은 typeid 연산자를 이용하는 것이다. 2011-1학기 프로그래밍언어및실습 (C++)
reinterpret_cast 강제 형 변환을 수행 unsigned short Hash( void *p ) { unsigned int val = reinterpret_cast<unsigned int>( p ); return ( unsigned short )( val ^ (val >> 16)); } 2011-1학기 프로그래밍언어및실습 (C++)
정리 클래스의 객체에 대해서 연산자를 사용할 수 있도록 만드는 기능을 연산자 오버로딩이라고 한다. 연산자 오버로딩은 연산자 함수에 의해서 구현된다. 연산자 함수는 클래스의 멤버 함수로 정의할 수도 있고, 전역 함수로 정의할 수도 있다. 클래스 형과 기본형 사이의 형 변환에 변환 생성자와 변환 연산자가 이용된다. 클래스 형을 다른 데이터 형으로 변환하려면 변환 연산자를 정의한다. C++은 형 변환의 의미를 명확히 구분해서 사용할 수 있도록 형 변환 연산자인 const_cast, static_cast, dynamic_cast, reinterpret_cast 연사자를 제공한다. 2011-1학기 프로그래밍언어및실습 (C++)