멤버함수 중첩( 복사 생성자 ) - 연사자 중첩 - 동적 메모리를 가지는 클래스를 지원 하도록 멤버 함수 작성 고급 함수들 멤버함수 중첩( 복사 생성자 ) - 연사자 중첩 - 동적 메모리를 가지는 클래스를 지원 하도록 멤버 함수 작성
중첩된(Overload) 멤버 함수 멤버 함수 중첩 (Overloading) 매개 변수의 수나 종류가 다른 같은 이름을 가진 멤버 함수 <Tip> 중첩 시 같은 코드를 중복 시키지 않도록 하는 것이 프로그램 수정 시 오류를 방지 할 수 있음
#include <iostream> class Rectangle { public: Rectangle(int width, int height); ~Rectangle(){} // overloading void DrawShape() const; void DrawShape(int aWidth, int aHeight) const; private: int itsWidth; int itsHeight; }; Rectangle::Rectangle(int width, int height) itsWidth = width; itsHeight = height; } list 10.1
void Rectangle::DrawShape() const { DrawShape( itsWidth, itsHeight); } void Rectangle::DrawShape(int width, int height) const for (int i = 0; i<height; i++) for (int j = 0; j< width; j++) std::cout << "*"; std::cout << "\n"; int main() Rectangle theRect(30,5); std::cout << "DrawShape(): \n"; theRect.DrawShape(); std::cout << "\nDrawShape(40,2): \n"; theRect.DrawShape(40,2); return 0;
기본값(Default value) 사용 클래스 멤버 함수도 기본값 사용 가능 기본값 사용 멤버 함수 vs. 중첩된 멤버 함수 합당한 기본값이 없을 때 전혀 다른 알고리즘을 사용할 때 매개변수 목록에서 다른 형을 사용하길 원할 때
#include <iostream> using namespace std; class Rectangle { public: // constructors Rectangle(int width, int height); ~Rectangle(){} void DrawShape(int aWidth, int aHeight, bool UseCurrentVals = false) const; private: int itsWidth; int itsHeight; }; Rectangle::Rectangle(int width, int height) itsWidth = width; itsHeight = height; } list 10.2
void Rectangle::DrawShape( int width, int height, bool UseCurrentValue) const { int printWidth; int printHeight; if (UseCurrentValue == true) printWidth = itsWidth; printHeight = itsHeight; } else printWidth = width; printHeight = height; for (int i = 0; i<printHeight; i++) for (int j = 0; j< printWidth; j++) cout << "*"; cout << "\n";
int main() { // initialize a rectangle to 30,5 Rectangle theRect(30,5); cout << "DrawShape(0,0,true)...\n"; theRect.DrawShape(0,0,true); cout <<"DrawShape(40,2)...\n"; theRect.DrawShape(40,2); return 0; }
기본 생성자(default constructor) 매개 변수가 없는 생성자 생성자가 없을 시 컴파일러가 자동 생성 하나의 사용자 생성자가 있다면 컴파일러는 자동 생성 하지 않음 프로그래머가 멤버 변수를 초기화 하기 위해 매개변수가 없는 기본 생성자를 만들 수 있음 생성자 중첩 생성자도 다른 멤버함수처럼 중첩 가능
#include <iostream> using namespace std; class Rectangle { public: Rectangle(); Rectangle(int width, int length); ~Rectangle() {} int GetWidth() const { return itsWidth; } int GetLength() const { return itsLength; } private: int itsWidth; int itsLength; }; Rectangle::Rectangle() itsWidth = 5; itsLength = 10; } Rectangle::Rectangle (int width, int length) itsWidth = width; itsLength = length; list 10.3
int main() { Rectangle Rect1; cout << "Rect1 width: " << Rect1.GetWidth() << endl; cout << "Rect1 length: " << Rect1.GetLength() << endl; int aWidth, aLength; cout << "Enter a width: "; cin >> aWidth; cout << "\nEnter a length: "; cin >> aLength; Rectangle Rect2(aWidth, aLength); cout << "\nRect2 width: " << Rect2.GetWidth() << endl; cout << "Rect2 length: " << Rect2.GetLength() << endl; return 0; }
객체 초기화 예) Rectangle::Rectangle(): itsWidth(5), itsLength(10) { } 초기화 단계에서 멤버변수를 초기화 할 수 있음 : 멤버변수(초기값), … , 멤버변수(초기값) 예) Rectangle::Rectangle(): itsWidth(5), itsLength(10) { } Rectangle::Rectangle (int width, int length): itsWidth(width), itsLength(length)
복사 생성자(Copy Constructor) 동일 클래스 형에 대한 참조자를 하나의 매개변수로 가지는 생성자 이를 const화 하는 것이 좋음 복사 생성자의 호출 객체 생성 시 자신의 클래스 형으로 된 객체를 인수로 전달하는 경우 CAT Tom(Frisky); CAT Tom = Frisky; 객체를 call by value로 전달 시 함수에 의해 객체 반환 시 기본 복사 생성자 컴파일러가 기본적으로 제공 각 멤버변수들을 새로운 객체의 멤버변수에 복사 CAT (const CAT & theCat) ; 얕은 복사 (shallow copy) 자유 기억 장소를 가리키는 포인터가 멤버변수로 있을 경우 문제 발생
얕은 복사 Cat newCat(oldCat) ; 둘 중 하나만 소멸 시 해결책 : 깊은 복사 (deep copy) oldCat 소멸자에 의해 자유기억공간 반환 존재하는 객체의 포인터는 실종된 포인터 해결책 : 깊은 복사 (deep copy) 복사 생성자를 통한 별도의 메모리 할당 oldCat newCat 자유공간에 대한포인터 oldCat newCat
#include <iostream> using namespace std; class CAT { public: CAT(); //default constructor CAT (const CAT &); // copy constructor ~CAT(); // destructor int GetAge() const { return *itsAge; } int GetWeight() const { return *itsWeight; } void SetAge(int age) { *itsAge = age; } private: int *itsAge; int *itsWeight; }; list 10.5
CAT::CAT() { itsAge = new int; itsWeight = new int; *itsAge = 5; *itsWeight = 9; } CAT::CAT(const CAT & rhs) *itsAge = rhs.GetAge(); *itsWeight = *(rhs.itsWeight); CAT::~CAT() delete itsAge; itsAge = 0; delete itsWeight; itsWeight = 0;
int main() { CAT frisky; cout << "frisky's age: " << frisky.GetAge() << endl; cout << "Setting frisky to 6...\n"; frisky.SetAge(6); cout << "Creating boots from frisky\n"; CAT boots(frisky); cout << "boots' age: " << boots.GetAge() << endl; cout << "setting frisky to 7...\n"; frisky.SetAge(7); cout << "boot's age: " << boots.GetAge() << endl; return 0; }
연산자 중첩 내장형(정수형, 실수형, 문자형) C++ class : 사용자 정의형 class에 대한 특정 기능의 구현 내장 연산자(+, -, *, /)를 가지고 있음 C++ class : 사용자 정의형 사용자 연산자 지원 가능 class에 대한 특정 기능의 구현 멤버함수를 이용하는 방법 연산자 중첩 내장형에 대한 중첩은 불가능 상식밖에 있는 연산자 중첩 금지
#include <iostream> using namespace std; class Counter { public: int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } private: int itsVal; }; Counter::Counter(): itsVal(0) {} int main() Counter i; cout << "The value of i is " << i.GetItsVal() << endl; return 0; } list 10.6
#include <iostream> using namespace std; class Counter { public: int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } void Increment() { ++itsVal; } void operator++ () { ++itsVal; } private: int itsVal; }; Counter::Counter(): itsVal(0) {} int main() Counter i; cout << "The value of i is " << i.GetItsVal() << endl; i.Increment(); ++i; return 0; } list 10.8
중첩 연산자 함수에서의 반환값 형 list 10.8의 문제점 Counter a = ++ i; 중첩 연산자 함수에서의 반환 연산자함수의 반환 형 없음 중첩 연산자 함수에서의 반환 임시 객체를 만든 뒤 이를 반환 (리스트 10.9) 이름 없는(nameless) 임시 객체 반환 (리스트 10.10) 값을 가지는 생성자를 가지는 경우 반환값으로 생성자의 결과를 반환 임시 객체를 만드는 비용 감소 this 포인터 사용 (리스트 10.11) Counter a = ++ i;
#include <iostream> using namespace std; class Counter { public: int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } void Increment() { ++itsVal; } Counter operator++ (); private: int itsVal; }; Counter::Counter(): itsVal(0) {} Counter Counter::operator++() ++itsVal; Counter temp; temp.SetItsVal(itsVal); return temp; } list 10.9
int main() { Counter i; cout << "The value of i is " << i.GetItsVal() << endl; i.Increment(); ++i; Counter a = ++i; cout << "The value of a: " << a.GetItsVal(); cout << " and i: " << i.GetItsVal() << endl; return 0 }
#include <iostream> using namespace std; class Counter { public: Counter(int val); ~Counter(){} int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } void Increment() { ++itsVal; } Counter operator++ (); private: int itsVal; }; Counter::Counter(): itsVal(0) {} Counter::Counter(int val):itsVal(val) Counter Counter::operator++() ++itsVal; return Counter (itsVal); } list 10.10
int main() { Counter i; cout << "The value of i is " << i.GetItsVal() << endl; i.Increment(); ++i; Counter a = ++i; cout << "The value of a: " << a.GetItsVal(); cout << " and i: " << i.GetItsVal() << endl; return 0; }
#include <iostream> using namespace std; class Counter { public: int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } void Increment() { ++itsVal; } const Counter& operator++ (); private: int itsVal; }; Counter::Counter(): itsVal(0) {}; const Counter& Counter::operator++() ++itsVal; return *this; } list 10.11
int main() { Counter i; cout << "The value of i is " << i.GetItsVal() << endl; i.Increment(); ++i; Counter a = ++i; cout << "The value of a: " << a.GetItsVal(); cout << " and i: " << i.GetItsVal() << endl; return 0; }
기타 상수형 반환 이유 Counter a = ++++ i; 후치 연산자 중첩 상수형 반환이 아니라면 위의 코드 작성 가능 상수형 반환 시 위의 코드 실행 불능 후치 연산자 중첩 컴파일러는 전치 후치 구분 방법? 후치 표시를 위해 관습적으로 연산자 선언에 정수 매개변수 이용 즉, 정수 매개변수를 이용은 않으나 매개변수가 있으며 후치임을 의미 후치 시 참조자에 의한 반환 불가능, 반드시 값을 반환 Counter a = ++++ i;
#include <iostream> using namespace std; class Counter { public: Counter(int initVal); Counter(const Counter& rhs); ~Counter(){} int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } const Counter& operator++ (); // 전치 const Counter operator++ (int); // 후치 private: int itsVal; }; list 10.12
Counter::Counter(): itsVal(0) {} Counter::Counter(int initVal): itsVal(initVal) Counter::Counter(const Counter& rhs): itsVal(rhs.itsVal) const Counter& Counter::operator++() { ++itsVal; return *this; } const Counter Counter::operator++(int theFlag) Counter temp(*this); return temp;
int main() { Counter i(3); cout << "The value of i is " << i.GetItsVal() << endl; i++; ++i; Counter a = ++i; cout << "The value of a: " << a.GetItsVal(); cout << " and i: " << i.GetItsVal() << endl; a = i++; return 0; }
이항 연산자의 중첩 a.operator+(b) varThree = varOne.Add( varTwo ); 단항 연산자처럼 만듦 : 단 매개변수를 하나 가진다는 점이 예외 a + b 멤버함수를 이용하는 것과 동일하지만 구문이 훨씬 자연스러움 Counter operator+ (const Counter &); a.operator+(b) Counter varOne, varTwo, varThree ; varThree = varOne.Add( varTwo ); varThree = varOne + varTwo ;
#include <iostream.h> using namespace std; class Counter { public: Counter(); Counter(int initialValue); ~Counter(){} int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } Counter Add(const Counter &); private: int itsVal; }; Counter::Counter(int initialValue): itsVal(initialValue) {} Counter::Counter(): itsVal(0) Counter Counter::Add(const Counter & rhs) return Counter(itsVal+ rhs.GetItsVal()); } list 10.13
int main() { Counter varOne(2), varTwo(4), varThree; varThree = varOne.Add(varTwo); cout << "varOne: " << varOne.GetItsVal()<< endl; cout << "varTwo: " << varTwo.GetItsVal() << endl; cout << "varThree: " << varThree.GetItsVal() << endl; return 0; }
#include <iostream> using namespace std; class Counter { public: Counter(int initialValue); ~Counter(){} int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } Counter operator+ (const Counter &); private: int itsVal; }; Counter::Counter(int initialValue): itsVal(initialValue) {} Counter::Counter(): itsVal(0) Counter Counter::operator+ (const Counter & rhs) return Counter(itsVal + rhs.GetItsVal()); } list 10.14
int main() { Counter varOne(2), varTwo(4), varThree; varThree = varOne + varTwo; cout << "varOne: " << varOne.GetItsVal()<< endl; cout << "varTwo: " << varTwo.GetItsVal() << endl; cout << "varThree: " << varThree.GetItsVal() << endl; return 0; }
대입 연산자 CAT catOne(5, 7) ; CAT catTwo(3, 4) ; // …. catTwo = catOne ; 지정하지 않아도 컴파일러가 제공 멤버변수를 각각 할당 멤버변수가 포인터인 경우 깊은 복사 안됨 catTwo 객체의 포인터가 원래 가리키던 메모리 누출 대입연산자를 새로 정의해 대입 시 포인터가 아니라 포인터가 가리키는 값을 직접 복사 자유기억공간 반납 후 재할당 받는 경우 자기 자신인지 반드시 확인 자기 자신을 반납해 버릴 수 있음 CAT catOne(5, 7) ; CAT catTwo(3, 4) ; // …. catTwo = catOne ;
#include <iostream> using namespace std; class CAT { public: int GetAge() const { return *itsAge; } int GetWeight() const { return *itsWeight; } void SetAge(int age) { *itsAge = age; } CAT & operator=(const CAT &); private: int *itsAge; int *itsWeight; }; CAT::CAT() itsAge = new int; itsWeight = new int; *itsAge = 5; *itsWeight = 9; } list 10.15
CAT & CAT::operator=(const CAT & rhs) { if (this == &rhs) return *this; *itsAge = rhs.GetAge(); *itsWeight = rhs.GetWeight(); } int main() CAT frisky; cout << "frisky's age: " << frisky.GetAge() << endl; cout << "Setting frisky to 6...\n"; frisky.SetAge(6); CAT whiskers; cout << "whiskers' age: " << whiskers.GetAge() << endl; cout << "copying frisky to whiskers...\n"; whiskers = frisky; return 0;
#include <iostream> using namespace std; class Eng { public: Eng( int num ); Eng & operator=(const Eng &); private: int itsNum; int *data; }; Eng::Eng( int num ) itsNum = num; data = new int[itsNum]; for( int i=0 ; i<itsNum ; i++ ) data[i] = 0; } list 10.15 심화
Eng & Eng::operator=(const Eng & rhs) { if (this == &rhs) return *this; delete data; itsNum = rhs.itsNum data = new int [itsNum] ; for( int i=0 ; i<itsNum ; i++ ) data[i] = rhs.data[i] ; } int main() Eng classA( 40 ); Eng classTemp( 10 ); … classTemp = classA; classA = classA return 0;
변환 연산자 1 class CAT { public: CAT(int val) ; …. }; 내장된 형의 변수 사용자 정의 클래스 객체 대입 내장된 형의 변수를 매개변수로 가지는 생성자를 통해 지원 class CAT { public: CAT(int val) ; …. }; … int main( ) int a = 5 ; CAT Frisky ; Frisky = a ; }
#include <iostream> using namespace std; class Counter { public: Counter(int val); ~Counter(){} int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } private: int itsVal; }; Counter::Counter(): itsVal(0) {} Counter::Counter(int val): itsVal(val) int main() int theShort = 5; Counter theCtr = theShort; cout << "theCtr: " << theCtr.GetItsVal() << endl; return 0; } list 10.17
변환 연산자 2 사용자 정의 클래스 객체 내장된 형의 변수 대입 클래스에 추가할 수 있는 변환 연산자 제공 변환 연산자는 반환값을 지정하지 못함 하지만 실제로는 값을 반환
#include <iostream> class Counter { public: Counter(); Counter(int val); ~Counter(){} int GetItsVal()const { return itsVal; } void SetItsVal(int x) {itsVal = x; } operator int (); private: int itsVal; }; Counter::Counter(): itsVal(0) {} Counter::Counter(int val): itsVal(val) Counter::operator unsigned short () return ( int (itsVal) ); } list 10.18
int main() { Counter ctr(5); int theShort = ctr; std::cout << "theShort: " << theShort << std::endl; return 0; }
Hw #3 복소수를 표시하기 위한 class를 제작 현재 복소수 값을 화면에 표시하기 위한 멤버함수를 작성해 보세요 이 class에 operator overloading을 이용하여 복소수의 사칙 연산이 가능하도록 하세요