참조자 - 참조자란무엇인가? - 참조자는어떻게만들고사용하는가? - 참조자는포인터와무엇이다른가? 1
참조자 (reference) 란? 참조자 : 객체 ( 타겟 ) 에대한다른이름 ( 별칭 ) 참조자의변화는타겟의변화 참조자만들고반드시초기화 참조자생성 형참조연산자 (&) 참조자이름 = 초기화타겟명 모든항목필수 예 ) int &rsomeref = someint ; 참조자에대한주소연산자 (&) 사용 참조사주소 = 타겟의주소 참조자에대입하기 ( 새로운타겟설정 ) 불능 2
#include <iostream> list 9.1 int main() using namespace std; int intone; int &rsomeref = intone; intone = 5; cout << "intone: " << intone << endl; cout << "rsomeref: " << rsomeref << endl; rsomeref = 7; cout << "intone: " << intone << endl; cout << "rsomeref: " << rsomeref << endl; return 0; 3
#include <iostream> list 9.2 int main() using namespace std; int intone; int &rsomeref = intone; intone = 5; cout << "intone: " << intone << endl; cout << "rsomeref: " << rsomeref << endl; cout << "&intone: " << &intone << endl; cout << "&rsomeref: " << &rsomeref << endl; return 0; 4
#include <iostream> list 9.3 int main() using namespace std; int intone; int &rsomeref = intone; intone = 5; cout << "intone:\t" << intone << endl; cout << "rsomeref:\t" << rsomeref << endl; cout << "&intone:\t" << &intone << endl; cout << "&rsomeref:\t" << &rsomeref << endl; int inttwo = 8; rsomeref = inttwo; cout << "\nintone:\t" << intone << endl; cout << "inttwo:\t" << inttwo << endl; cout << "rsomeref:\t" << rsomeref << endl; cout << "&intone:\t" << &intone << endl; cout << "&inttwo:\t" << &inttwo << endl; cout << "&rsomeref:\t" << &rsomeref << endl; return 0; 5
무엇이참조될수있는가? 참조대상 ( 사용자정의한것을포함한 ) 모든객체 int &rintref = int ; (X) int howbig = 200 ; int &rintref = howbig ; (O) Cat &rcatref = Cat ; (X) Cat Frisky ; Cat &rcatref = Frisky (O) 포인터와달리참조자는널 (null) 이될수없음 6
#include <iostream> list 9.4 class SimpleCat public: SimpleCat (int age, int weight); ~SimpleCat() int GetAge() return itsage; int GetWeight() return itsweight; private: int itsage; int itsweight; ; SimpleCat::SimpleCat(int age, int weight) itsage = age; itsweight = weight; 7
int main() SimpleCat Frisky(5,8); SimpleCat & rcat = Frisky; std::cout << "Frisky is: "; std::cout << Frisky.GetAge() << " years old. \n"; std::cout << "And Frisky weights: "; std::cout << rcat.getweight() << " pounds. \n"; return 0; 8
함수인자 (argument) 를참조자로전달 함수의한계 매개변수에값으로전달 (call by value) 반환값이하나밖에없음 참조에의한전달 (call by reference) 포인터를이용하는방법 참조자를전달하는방법 포인터를사용할때의기능 + 일반변수사용시의편리성동시제공 9
#include <iostream> list 9.5 using namespace std; void swap(int x, int y); int main() int x = 5, y = 10; cout <<"Main. Before swap, x:"<<x<< "y:"<<y<<"\n"; swap(x,y); cout <<"Main. After swap, x: <<x<<" y: "<<y<<"\n"; return 0; void swap (int x, int y) int temp; cout <<"Swap. Before swap, x:"<<x<<" y: "<<y<<"\n"; temp = x; x = y; y = temp; cout <<"Swap. After swap, x: "<<x<<" y: "<<y<< "\n"; 10
#include <iostream> list 9.6 using namespace std; void swap(int *x, int *y); int main() int x = 5, y = 10; cout <<"Main. Before swap, x: "<<x<<" y: "<<y<<"\n"; swap(&x,&y); cout << "Main. After swap, x: "<<x<<" y: "<<y<<"\n"; return 0; void swap (int *px, int *py) int temp; cout << "Swap. Before swap, *px: " << *px << " *py: " << *py << "\n"; temp = *px; *px = *py; *py = temp; cout << "Swap. After swap, *px: " << *px << " *py: " << *py << "\n"; 11
#include <iostream> list 9.7 using namespace std; void swap(int &x, int &y); int main() int x = 5, y = 10; cout <<"Main. Before swap, x: "<<x<<" y: "<<y<<"\n"; swap(x,y); cout <<"Main. After swap, x: "<<x<<" y: "<<y<<"\n"; return 0; void swap (int &rx, int &ry) int temp; cout << "Swap. Before swap, rx: " << rx << " ry: " << ry << "\n"; temp = rx; rx = ry; ry = temp; cout << "Swap. After swap, rx: " << rx << " ry: " << ry << "\n"; 12
함수헤더와함수원형 (prototype) 에대한이해 함수원형을통해참조에의한전달임을알수있음 C++ 의목적은프로그래머들이잘만들어진클래스와함수들에대해그내부구조는모르는채잘쓸수있게하는것이다. 이각부분들은전체프로그램을만들기위해조립만되면되는것이다. 마치건물과다리를만들때재료들을가져다조립만하면되듯이말이다. 똑같은방식으로기술자는파이프의하중, 용량, 크기등을결정할때사양서만보면된다. 똑같은방식으로프로그래머는클래스나함수의인터페이스부분만보고, 어떤서비스를하는지어떤매개변수를갖는지반환값이무엇인지를알게된다. 13
여러개의값을반환하는방법 함수는하나의값을반환 해결책 값을반환받기위한참조자 / 포인터를함수에전달 return 을통한반환은오류코드등의다른목적위해사용 14
#include <iostream> list 9.8 using namespace std; short Factor(int n, int* psquared, int* pcubed); int main() int number, squared, cubed; short error; cout << "Enter a number (0-20): "; cin >> number; error = Factor(number, &squared, &cubed); if (!error) cout << "number: " << number << "\n"; cout << "square: " << squared << "\n"; cout << "cubed: " << cubed << "\n"; else cout << "Error encountered!!\n"; return 0; 15
short Factor(int n, int *psquared, int *pcubed) short Value = 0; if (n > 20) Value = 1; else *psquared = n*n; *pcubed = n*n*n; Value = 0; return Value; 16
#include <iostream> list 9.9 using namespace std; typedef unsigned short USHORT; enum ERR_CODE SUCCESS, ERROR ; ERR_CODE Factor(USHORT, USHORT&, USHORT&); int main() USHORT number, squared, cubed; ERR_CODE result; cout << "Enter a number (0-20): "; cin >> number; result = Factor(number, squared, cubed); if (result == SUCCESS) cout << "number: " << number << "\n"; cout << "square: " << squared << "\n"; cout << "cubed: " << cubed << "\n"; else cout << "Error encountered!!\n"; return 0; 17
ERR_CODE Factor(USHORT n, USHORT &rsquared, USHORT &rcubed) if (n > 20) return ERROR; else rsquared = n*n; rcubed = n*n*n; return SUCCESS; 18
효율성을위해참조자를전달 함수에객체를전달할때마다그객체의복사가발생 ( 복사생성자함수호출 ) 함수로부터객체가반환될때도복사발생 시간 / 메모리소요 ( 큰객체일수록비용증대 ) 참조 (call by reference) 방식을쓰는이유 1. 값의변경을위해 2. 효율성증대를위해 19
#include <iostream> list 9.10 using namespace std; class SimpleCat public: SimpleCat (); SimpleCat(SimpleCat&); ~SimpleCat(); ; SimpleCat::SimpleCat() cout << "Simple Cat Constructor...\n"; SimpleCat::SimpleCat(SimpleCat&) cout << "Simple Cat Copy Constructor...\n"; SimpleCat::~SimpleCat() cout << "Simple Cat Destructor...\n"; 20
SimpleCat FunctionOne (SimpleCat thecat); SimpleCat* FunctionTwo (SimpleCat *thecat); int main() cout << "Making a cat...\n"; SimpleCat Frisky; cout << "Calling FunctionOne...\n"; FunctionOne(Frisky); cout << "Calling FunctionTwo...\n"; FunctionTwo(&Frisky); return 0; SimpleCat FunctionOne(SimpleCat thecat) cout << "Function One. Returning...\n"; return thecat; SimpleCat* FunctionTwo (SimpleCat *thecat) cout << "Function Two. Returning...\n"; return thecat; 21
상수포인터 (const pointer) 전달 객체의포인터전달시효율성증대 그러나, 원치않은값의변경가능 ( 위험요소 ) 상수포인터를사용함으로써값의변경차단 상수참조자사용시보다쉽게구현 22
#include <iostream> list 9.11 using namespace std; class SimpleCat public: SimpleCat(); SimpleCat(SimpleCat&) cout << "Simple Cat Copy Constructor...\n"; ~SimpleCat(); cout << "Simple Cat Destructor...\n"; int GetAge() const return itsage; void SetAge(int age) itsage = age; private: int itsage; ; SimpleCat::SimpleCat() cout << "Simple Cat Constructor...\n"; itsage = 1; 23
const SimpleCat * const FunctionTwo (const SimpleCat * const thecat); int main() cout << "Making a cat...\n"; SimpleCat Frisky; cout <<"Frisky is "<<Frisky.GetAge()<<" years old\n"; int age = 5; Frisky.SetAge(age); cout <<"Frisky is "<<Frisky.GetAge()<<" years old\n"; cout << "Calling FunctionTwo...\n"; FunctionTwo(&Frisky); cout <<"Frisky is "<<Frisky.GetAge()<<" years old\n"; return 0; const SimpleCat * const FunctionTwo (const SimpleCat * const thecat) cout << "Function Two. Returning...\n"; cout << "Frisky is now " << thecat->getage(); cout << " years old \n"; // thecat->setage(8); const! return thecat; 24
#include <iostream> list 9.12 using namespace std; class SimpleCat public: SimpleCat(); SimpleCat(SimpleCat&) cout << "Simple Cat Copy Constructor...\n"; ~SimpleCat(); cout << "Simple Cat Destructor...\n"; int GetAge() const return itsage; void SetAge(int age) itsage = age; private: int itsage; ; SimpleCat::SimpleCat() cout << "Simple Cat Constructor...\n"; itsage = 1; 25
const SimpleCat &FunctionTwo (const SimpleCat & thecat); int main() cout << "Making a cat...\n"; SimpleCat Frisky; cout <<"Frisky is "<<Frisky.GetAge()<<" years old\n"; int age = 5; Frisky.SetAge(age); cout <<"Frisky is "<<Frisky.GetAge()<<" years old\n"; cout << "Calling FunctionTwo...\n"; FunctionTwo(&Frisky); cout <<"Frisky is "<<Frisky.GetAge()<<" years old\n"; return 0; const SimpleCat &FunctionTwo (const SimpleCat & thecat) cout << "Function Two. Returning...\n"; cout << "Frisky is now " << thecat.getage(); cout << " years old \n"; // thecat.setage(8); const! return thecat; 26
참조자와포인터를사용하는때 사용하기쉬움 참조자 - 선호 ( 가능하면매개변수및반환값을참조자로사용 ) 포인터 참조자에 비해 사용하기 번거로움 상대적으로융통성부족 - 재할당되지않음 -Null 이될수없음 융통성을제공 - 재할당가능 -Null 이가능 New에의한자유기억공간할당시사용 참조자 (&) / 포인터 (*) 선언시기호의위치 Cat& Frisky ; Cat & Frisky ; Cat &Frisky ; 27
범위를벗어난객체에대한참조자반환오류 참조자사용시 참조자는무엇을가리키는가? 그객체가지금존재하는가? 28
#include <iostream> list 9.13 class SimpleCat public: SimpleCat (int age, int weight); ~SimpleCat() int GetAge() return itsage; int GetWeight() return itsweight; private: int itsage; int itsweight; ; SimpleCat::SimpleCat(int age, int weight) itsage = age; itsweight = weight; 29
SimpleCat &TheFunction(); int main() SimpleCat &rcat = TheFunction(); int age = rcat.getage(); std::cout << "rcat is " << age << " years old!\n"; return 0; SimpleCat &TheFunction() SimpleCat Frisky(5,9); return Frisky; 30
힙에있는객체에대한참조자반환 힙에있는객체에대한참조자반환시 메모리 ( 힙 ) 제거에신경 메모리제거후참조자사용중지 힙사용시포인터사용바람직 31
#include <iostream> list 9.14 class SimpleCat public: SimpleCat (int age, int weight); ~SimpleCat() int GetAge() return itsage; int GetWeight() return itsweight; private: int itsage; int itsweight; ; SimpleCat::SimpleCat(int age, int weight) itsage = age; itsweight = weight; 32
int main() SimpleCat & rcat = TheFunction(); int age = rcat.getage(); std::cout << "rcat is " << age << " years old!\n"; std::cout << "&rcat: " << &rcat << std::endl; // How do you get rid of that memory? SimpleCat * pcat = &rcat; delete pcat; // Uh oh, rcat now refers to?? return 0; SimpleCat &TheFunction() SimpleCat * pfrisky = new SimpleCat(5,9); std::cout << "pfrisky: " << pfrisky << std::endl; return *pfrisky; 33