Chapter 05. const, friend, static 박종혁교수 UCS Lab Tel: 970-6702 Email: jhpark1@seoultech.ac.kr SeoulTech 2018-2 nd 프로그래밍입문 (2)
Chapter 05-1. const 멤버변수, 함수, 객체
const 멤버변수 멤버변수에 const 를붙이는경우 class Car public: const int serial; string color;... Car(int s, string c) : serial(s) color = c; 이멤버변수의값을변경할수없다.
4 const 멤버함수 멤버함수의상수화 함수내부에서멤버변수의값을변경할수없음 이함수내에서상수화되지않은함수의호출을허용하지않음 멤버변수의포인터의리턴을허용하지않음 사용예 void ShowData() const cout<<" 이름 : "<<name<<endl; cout<<" 나이 : "<<age<<endl; cout<<" 학번 : "<<id<<endl; cout<<" 학과 : "<<major<<endl;
멤버함수에 const 를붙이는경우 void displayinfo() const cout << " 속도 : " << speed << endl; cout << " 기어 : " << gear << endl; cout << " 색상 : " << color << endl; 이함수안에서는멤버변수의값을변경할수없다.
6 const 멤버함수예 #include <iostream> using std::cout; using std::endl; class Count int cnt; public : Count() : cnt(0) int* GetPtr() const return &cnt; void Increment() cnt++; // Compile Error int main() Count count; count.increment(); count.showdata(); return 0; ; void ShowData() const ShowIntro(); // Compile Error cout<<cnt<<endl; void ShowIntro() cout<<" 현재 count의값 : "<<endl;
7 const 객체 const 객체 데이터의변경이허용되지않는객체 const 함수이외에는호출불가 const와함수오버로딩 const도함수오버로딩조건에포함 void function(int n) const..... void function(int n).....
객체에 const 를붙이는경우 int main() const Car c1(0, 1, "yellow"); c1.setspeed(); // 오류! return 0;
9 const 로선언된객체를대상으로는 const 로선언되지않는 멤버함수의호출이불가능함 이객체의데이터변경을허용하지않겠다!
10 const 와함수오버로딩 const 객체또는참조자를대상으로멤버함수 호출시 const 선언된멤버함수가호출된다! 함수의 const 선언유무는함수오버 로딩의조건이된다! 실행결과
11 ConstOverloading.cpp #include <iostream> using namespace std; class SoSimple private: int num; public: SoSimple(int n) : num(n) SoSimple& AddNum(int n) num+=n; return *this; void SimpleFunc () cout<<"simplefunc: "<<num<<endl; void SimpleFunc () const cout<<"const SimpleFunc: "<<num<<endl; ; void YourFunc(const SoSimple &obj) obj.simplefunc(); int main(void) SoSimple obj1(2); const SoSimple obj2(7); obj1.simplefunc(); obj2.simplefunc(); YourFunc(obj1); YourFunc(obj2); return 0;
12 생각해봅시다 - 어느예제가에러날까? - 왜에러가날까? 예1) #include <iostream> using std::cout; using std::endl; class AAA int num; public : AAA(int _num) : num(_num) void Add(int n) num+=n; void ShowData() cout<<num<<endl; ; int main() const AAA aaa(10); aaa.add(10); return 0; 예 2) #include <iostream> using std::cout; using std::endl; class AAA int num; public : AAA(int _num) : num(_num) void ShowData() cout<<"void ShowData() 호출 "<<endl; cout<<num<<endl; void ShowData() const cout<<"void ShowData() const 호출 "<<endl; cout<<num<<endl; ; int main() const AAA aaa1(20); AAA aaa2(70); aaa1.showdata(); aaa2.showdata(); return 0;
13 생각해봅시다 - 어느예제가에러날까? - 왜에러가날까? 예1) #include <iostream> using std::cout; using std::endl; class AAA int num; public : AAA(int _num) : num(_num) void Add(int n) num+=n; void ShowData() cout<<num<<endl; ; int main() const AAA aaa(10); aaa.add(10); // Compile Error aaa.showdata(); // Compile Error return 0; 예 2) #include <iostream> using std::cout; using std::endl; class AAA int num; public : AAA(int _num) : num(_num) void ShowData() cout<<"void ShowData() 호출 "<<endl; cout<<num<<endl; void ShowData() const cout<<"void ShowData() const 호출 "<<endl; cout<<num<<endl; ; int main() const AAA aaa1(20); AAA aaa2(70); aaa1.showdata(); // void ShowData() const 호출 aaa2.showdata(); // void ShowData() 호출 return 0;
Chapter 05-2. friend 선언
15 친구란? 친구? 내가족의일원은아니지만내가족과동일한권한을가진일원으로인정받은사람 우리집냉장고 우리집 TV 친구 내침대 우리집식탁
16 C++ 프렌드 프렌드함수 클래스의멤버함수가아닌외부함수 전역함수 다른클래스의멤버함수 friend 키워드로클래스내에선언된함수 클래스의모든멤버를접근할수있는권한부여 프렌드함수라고부름 프렌드선언의필요성 클래스의멤버로선언하기에는무리가있고, 클래스의모든멤버를자유롭게접근할수있는일부외부함수작성시
17 프렌드로초대하는 3 가지유형 프렌드함수가되는 3 가지 전역함수 : 클래스외부에선언된전역함수 다른클래스의멤버함수 : 다른클래스의특정멤버함수 다른클래스전체 : 다른클래스의모든멤버함수
18 클래스의 friend 선언 Girl 클래스에대한 friend 선언! - friend 선언은 private 멤버의접근을허용 - friend 선언은정보은닉에반하는선언이기 때문에매우제한적으로선언되어야한다. Girl 이 Boy 의 friend 로선언되었 으므로, private 멤버에직접접근 가능
19 Friend 선언예제 #include <iostream> #include <cstring> using namespace std; class Girl; class Boy private: int height; friend class Girl; public: Boy(int len) : height(len) void ShowYourFriendInfo(Girl &frn); ; class Girl private: char phnum[20]; public: Girl(char * num) strcpy(phnum, num); void ShowYourFriendInfo(Boy &frn); friend class Boy; ; void Boy::ShowYourFriendInfo(Girl &frn) cout<<"her phone number: "<<frn.phnum<<endl; void Girl::ShowYourFriendInfo(Boy &frn) cout<<"his height: "<<frn.height<<endl; int main(void) Boy boy(170); Girl girl("010-1234-5678"); boy.showyourfriendinfo(girl); girl.showyourfriendinfo(boy); return 0;
20 함수의 friend 선언 전역변수대상의 friend 선언 이렇듯클래스의특정멤버함수를대상 으로도 friend 선언이가능하다. private 멤버접근 private 멤버접근 private 멤버접근
21 MyFriendFunction.cpp #include <iostream> using namespace std; class Point; class PointOP private: int opcnt; public: PointOP() : opcnt(0) ; Point PointAdd(const Point&, const Point&); Point PointSub(const Point&, const Point&); ~PointOP() cout<<"operation times: "<<opcnt<<endl; class Point private: int x; int y; public: Point(const int &xpos, const int &ypos) : x(xpos), y(ypos) friend Point PointOP::PointAdd(const Point&, const Point&); friend Point PointOP::PointSub(const Point&, const Point&); friend void ShowPointPos(const Point&); ; Point PointOP::PointAdd(const Point& pnt1, const Point& pnt2) opcnt++; return Point(pnt1.x+pnt2.x, pnt1.y+pnt2.y); Point PointOP::PointSub(const Point& pnt1, const Point& pnt2) opcnt++; return Point(pnt1.x-pnt2.x, pnt1.y-pnt2.y); int main(void) Point pos1(1, 2); Point pos2(2, 4); PointOP op; ShowPointPos(op.PointAdd(pos1, pos2)); ShowPointPos(op.PointSub(pos2, pos1)); return 0; void ShowPointPos(const Point& pos) cout<<"x: "<<pos.x<<", "; cout<<"y: "<<pos.y<<endl;
Chapter 05-3. static
23 정적멤버 (static member) 정적멤버 같은클래스형으로선언된여러객체들이동일한하나의자료를공유 클래스의정의시멤버를 static이란키워드로정의 클래스내에선언된정적멤버는정적멤버가선언된클래스로사용영역이제한된전역변수 (global variable) 클래스내에서정적멤버를선언할때정적멤버자체가정의되는것은아니기때문에클래스밖에서정적멤버를정의하는선언필요 모든정적멤버변수는특별히초기값을명시하지않는한 0으로초기화
24 정적멤버 (static member) Static 멤버의등장 전역변수와전역함수를일부대처하기위해등장 Static 키워드의효과 모든객체가공유할수있는멤버
25 정적멤버 (static member) static 멤버의특징 클래스변수, 클래스함수라한다. main 함수호출이전에메모리공간에올라가서초기화 ( 전역변수와동일 ) 선언된클래스의객체내에직접접근허용 static 멤버초기화문으로초기화해야함
26 static 멤버와 non-static 멤버의특성 static 변수와함수에대한기억부류의한종류 생명주기 프로그램이시작될때생성, 프로그램종료시소멸 사용범위 선언된범위, 접근지정에따름 클래스의멤버 static 멤버 프로그램이시작할때생성 클래스당하나만생성, 클래스멤버라고불림 클래스의모든인스턴스 ( 객체 ) 들이공유하는멤버 non-static 멤버 객체가생성될때함께생성 객체마다객체내에생성 인스턴스멤버라고불림
27 전역변수가필요한상황 객체지향이기때문에전역변수를사용할것을권하지않음 #include <iostream> using namespace std; int simobjcnt=0; int cmxobjcnt=0; class SoSimple public: SoSimple() simobjcnt++; cout<<simobjcnt<<" 번째 SoSimple 객체 "<<endl; ; class SoComplex public: SoComplex() cmxobjcnt++; cout<<cmxobjcnt<<" 번째 SoComplex 객체 "<<endl; ; SoComplex(SoComplex ©) cmxobjcnt++; cout<<cmxobjcnt<<" 번째 SoComplex 객체 "<<endl; int main(void) SoSimple sim1; SoSimple sim2; SoComplex com1; SoComplex com2=com1; SoComplex(); return 0;
28 static 멤버변수 ( 클래스변수 ) static 변수는객체별로존재하는변수가아닌, 프로그램전 체영역에서하나만존재하는변수이다. 프로그램실행과동시에초기화되어메모리공간에할당된다.
29 StaticMember.cpp #include <iostream> using namespace std; class SoSimple private: static int simobjcnt; public: SoSimple() simobjcnt++; cout<<simobjcnt<<" 번째 SoSimple 객체 "<<endl; ; int SoSimple::simObjCnt=0; class SoComplex private: static int cmxobjcnt; public: SoComplex() cmxobjcnt++; cout<<cmxobjcnt<<" 번째 SoComplex 객체 "<<endl; SoComplex(SoComplex ©) cmxobjcnt++; cout<<cmxobjcnt<<" 번째 SoComplex 객체 "<<endl; ; int SoComplex::cmxObjCnt=0; int main(void) SoSimple sim1; SoSimple sim2; SoComplex cmx1; SoComplex cmx2=cmx1; SoComplex(); return 0;
30 C 언어에서이야기한 static 실행결과
31 static 멤버사용 : 객체의멤버로접근 static 멤버는객체이름이나객체포인터로접근 보통멤버처럼접근할수있음 객체.static 멤버객체포인터 ->static 멤버 Person 타입의객체 lee 와포인터 p 를이용하여 static 멤버를접근하는예 Person lee; lee.sharedmoney = 500; // 객체.static 멤버방식 Person *p; p = &lee; p->addshared(200); // 객체포인터 ->static 멤버방식
#include <iostream> using namespace std; class Person public: double money; // 개인소유의돈 void addmoney(int money) this->money += money; ; static int sharedmoney; // 공금 static void addshared(int n) sharedmoney += n; // static 변수생성. 전역공간에생성 int Person::sharedMoney=10; // 10 으로초기화 - 출력결과는? - 각변수값들이어떻게변경될까생각해봅시다. 32 // main() 함수 int main() Person han; han.money = 100; // han 의개인돈 =100 han.sharedmoney = 200; // static 멤버접근, 공금 =200 Person lee; lee.money = 150; // lee 의개인돈 =150 lee.addmoney(200); // lee 의개인돈 =350 lee.addshared(200); // static 멤버접근, 공금 =400 cout << han.money << ' ' << lee.money << endl; cout << han.sharedmoney << ' ' << lee.sharedmoney << endl;
#include <iostream> using namespace std; 33 class Person public: double money; // 개인소유의돈 void addmoney(int money) this->money += money; ; static int sharedmoney; // 공금 static void addshared(int n) sharedmoney += n; // static 변수생성. 전역공간에생성 int Person::sharedMoney=10; // 10 으로초기화 // main() 함수 int main() Person han; han.money = 100; // han 의개인돈 =100 han.sharedmoney = 200; // static 멤버접근, 공금 =200 Person lee; lee.money = 150; // lee 의개인돈 =150 lee.addmoney(200); // lee 의개인돈 =350 lee.addshared(200); // static 멤버접근, 공금 =400 cout << han.money << ' ' << lee.money << endl; cout << han.sharedmoney << ' ' << lee.sharedmoney << endl; 100 350 400 400 han 과 lee 의 money 는각각 100, 350 han 과 lee 의 sharedmoney 는공통 400
#include <iostream> using namespace std; class Person public: double money; // 개인소유의돈 void addmoney(int money) this->money += money; main() 이시작하기직전 sharedmoney 10 addshared()... sharedmoney 10 200 addshared()... 34 ; static int sharedmoney; // 공금 static void addshared(int n) sharedmoney += n; Person han; han.money = 100; han.sharedmoney = 200; han money 100 addmoney()... // static 변수생성. 전역공간에생성 int Person::sharedMoney=10; // 10 으로초기화 // main() 함수 int main() Person han; han.money = 100; // han 의개인돈 =100 han.sharedmoney = 200; // static 멤버접근, 공금 =200 Person lee; lee.money = 150; // lee 의개인돈 =150 lee.addmoney(200); // lee 의개인돈 =350 lee.addshared(200); // static 멤버접근, 공금 =400 cout << han.money << ' ' << lee.money << endl; cout << han.sharedmoney << ' ' << lee.sharedmoney << endl; 100 350 400 400 han 과 lee 의 money 는각각 100, 350 Person lee; lee.money = 150; lee.addmoney(200); lee.addshared(200); sharedmoney 200 addshared()... han lee money 100 money 150350 addmoney()... addmoney()... sharedmoney 200400 addshared()... han lee money 100 money 350 han 과 lee 의 sharedmoney 는공통 400 addmoney()... addmoney()...
static 멤버사용 : 클래스명과범위지정연산자 (::) 로접근 35 클래스이름과범위지정연산자 (::) 로접근가능 static 멤버는클래스마다오직한개만생성되기때문 클래스명 ::static 멤버 han.sharedmoney = 200; <-> Person::sharedMoney = 200; lee.addshared(200); <-> Person::addShared(200); non-static 멤버는클래스이름을접근불가 Person::money = 100; // 컴파일오류. non-static 멤버는클래스명으로접근불가 Person::addMoney(200); // 컴파일오류. non-static 멤버는클래스명으로접근불가
#include <iostream> using namespace std; class Person public: double money; // 개인소유의돈 void addmoney(int money) this->money += money; ; static int sharedmoney; // 공금 static void addshared(int n) sharedmoney += n; // static 변수생성. 전역공간에생성 int Person::sharedMoney=10; // 10 으로초기화 - 출력결과는? - 각변수값들이어떻게변경될까생각해봅시다. // main() 함수 int main() Person::addShared(50); // static 멤버접근, 공금 =60 cout << Person::sharedMoney << endl; Person han; han.money = 100; han.sharedmoney = 200; // static 멤버접근, 공금 =200 Person::sharedMoney = 300; // static 멤버접근, 공금 =300 Person::addShared(100); // static 멤버접근, 공금 =400 cout << han.money << ' ' << Person::sharedMoney << endl;
#include <iostream> using namespace std; class Person public: double money; // 개인소유의돈 void addmoney(int money) this->money += money; ; static int sharedmoney; // 공금 static void addshared(int n) sharedmoney += n; // static 변수생성. 전역공간에생성 int Person::sharedMoney=10; // 10 으로초기화 han 객체가생기기전부터 // main() 함수 static 멤버접근 int main() Person::addShared(50); // static 멤버접근, 공금 =60 cout << Person::sharedMoney << endl; Person han; han.money = 100; han.sharedmoney = 200; // static 멤버접근, 공금 =200 Person::sharedMoney = 300; // static 멤버접근, 공금 =300 Person::addShared(100); // static 멤버접근, 공금 =400 cout << han.money << ' ' << Person::sharedMoney << endl; 60 100 400 sharedmoney 400 han 의 money 100 37
#include <iostream> using namespace std; main() 이시작하기직전 sharedmoney 10 addshared()... class Person public: double money; // 개인소유의돈 void addmoney(int money) this->money += money; Person::addShared(50); sharedmoney 10 addshared()... 60 ; static int sharedmoney; // 공금 static void addshared(int n) sharedmoney += n; // static 변수생성. 전역공간에생성 int Person::sharedMoney=10; // 10 으로초기화 han 객체가생기기전부터 // main() 함수 static 멤버접근 int main() Person::addShared(50); // static 멤버접근, 공금 =60 cout << Person::sharedMoney << endl; Person han; han.money = 100; han.sharedmoney = 200; // static 멤버접근, 공금 =200 Person::sharedMoney = 300; // static 멤버접근, 공금 =300 Person::addShared(100); // static 멤버접근, 공금 =400 Person han; han.money = 100; han.sharedmoney = 200; han han sharedmoney 60 addshared()... money addmoney()... sharedmoney 200 addshared()... money 100 addmoney()... cout << han.money << ' ' << Person::sharedMoney << endl; 60 100 400 han 의 money 100 sharedmoney 400 Person::sharedMoney = 300; Person::addShared(100); han sharedmoney 200 addshared()... money 100 300 400 38 addmoney()...
참고문헌 뇌를자극하는 C++ 프로그래밍, 이현창, 한빛미디어, 2011 열혈 C++ 프로그래밍 ( 개정판 ), 윤성우, 오렌지미디어, 2012 C++ ESPRESSO, 천인국저, 인피니티북스, 2011 명품 C++ Programming, 황기태, 생능출판사, 2013 39
Q & A
추가자료
42 C 의 const const double PI=3.14; PI=3.1415; // 컴파일오류 const int val; val=20; // 컴파일오류
43 C 의 const int n=10; const int* pn=&n; *pn=20; // 컴파일오류 int n1=10; int n2=20; int* const pn=&n1; *pn=20; pn=&n2; // 컴파일오류
44 멤버변수의상수화 #include<iostream> using std::cout; using std::endl; class Student const int id; int age; char name[20]; char major[30]; public: Student(int _id, int _age, char* _name, char* _major) id=_id; //error age=_age; strcpy(name, _name); strcpy(major, _major); ; void ShowData() cout<<" 이름 : "<<name<<endl; cout<<" 나이 : "<<age<<endl; cout<<" 학번 : "<<id<<endl; cout<<" 학과 : "<<major<<endl; int main() Student Kim(200577065, 20, "Kim Gil Dong", "Computer Eng."); Student Hong(200512065, 19, "Hong Gil Dong", "Electronics Eng."); Kim.ShowData(); cout<<endl; Hong.ShowData(); return 0; 컴파일에러 상수값을생성자에서초기화하여발생 Member initializer 사용 Const 멤버변수초기화
45 멤버변수의상수화 #include<iostream> using std::cout; using std::endl; class Student const int id; int age; char name[20]; char major[30]; public: Student(int _id, int _age, char* _name, char* _major) : id(_id), age(_age) strcpy(name, _name); strcpy(major, _major); void ShowData() cout<<" 이름 : "<<name<<endl; cout<<" 나이 : "<<age<<endl; cout<<" 학번 : "<<id<<endl; cout<<" 학과 : "<<major<<endl; ; int main() Initializer 는 Student Kim(200577065, 20, "Kim Gil Dong", "Computer Eng."); Student Hong(200512065, 19, "Hong Gil Dong", "Electronics Eng."); Kim.ShowData(); cout<<endl; Hong.ShowData(); return 0; 생성자함수호출전에초기화됨.
46 const 멤버함수예 #include <iostream> using std::cout; using std::endl; class Count int cnt; public : Count() : cnt(0) const int* GetPtr() const return &cnt; void Increment() cnt++; ; void ShowData() const ShowIntro(); cout<<cnt<<endl; void ShowIntro() const cout<<" 현재 count 의값 : "<<endl; int main() Count count; count.increment(); count.increment(); count.showdata(); return 0;
47 static 멤버변수의접근방법 접근 case 2 접근 case 1 접근 case 3 static 변수가선언된외부에서의접근이가능하려면, 해당변수가 public 으로선언되어야한다. 실행결과
48 PublicStaticMember #include <iostream> using namespace std; class SoSimple public: static int simobjcnt; public: SoSimple() simobjcnt++; ; int SoSimple::simObjCnt=0; int main(void) cout<<sosimple::simobjcnt<<" 번째 SoSimple 객체 "<<endl; SoSimple sim1; SoSimple sim2; cout<<sosimple::simobjcnt<<" 번째 SoSimple 객체 "<<endl; cout<<sim1.simobjcnt<<" 번째 SoSimple 객체 "<<endl; cout<<sim2.simobjcnt<<" 번째 SoSimple 객체 "<<endl; return 0;
49 static 멤버함수 static 멤버변수의특징과일치한다. static 함수는객체내에존재하는함수가아니기때문에멤버변수나멤버함수에접근이불가능하다. static 함수는 static 변수에만접근가능하고, static 함수만호출가능하다.
50 const static 멤버와 mutable const static 멤버변수는, 클래스가정의될때지정된값이유지되는상수이기때문에, 위예제에서보이는바와같이초기화가가능하도록문법으로정의하고있다. mutable 로선언된멤버변수는 const 함수내에 서값의변경이가능하다.
51 ConstStaticMember.cpp #include <iostream> using namespace std; class CountryArea public: const static int RUSSIA =1707540; const static int CANADA =998467; const static int CHINA =957290; const static int SOUTH_KOREA =9922; ; int main(void) cout<<" 러시아면적 : "<<CountryArea::RUSSIA<<" km2 "<<endl; cout<<" 캐나다면적 : "<<CountryArea::CANADA<<" km2 "<<endl; cout<<" 중국면적 : "<<CountryArea::CHINA<<" km2 "<<endl; cout<<" 한국면적 : "<<CountryArea::SOUTH_KOREA<<" km2 "<<endl; return 0;
52 Mutable.cpp #include <iostream> using namespace std; class SoSimple private: int num1; mutable int num2; public: SoSimple(int n1, int n2) : num1(n1), num2(n2) void ShowSimpleData() const cout<<num1<<", "<<num2<<endl; void CopyToNum2() const num2=num1; ; int main(void) SoSimple sm(1, 2); sm.showsimpledata(); sm.copytonum2(); sm.showsimpledata(); return 0;
53 explicit & mutable explicit 명시적호출만허용한다. mutable const 에예외를둔다
54 explicit & mutable /* explicit.cpp */ #include<iostream> using std::cout; using std::endl; class AAA public: explicit AAA(int n) cout<<"explicit AAA(int n)"<<endl; ; 컴파일에러발생!! - Explicit 로선언되어, main 함수에서 AAA(10) 으로수정되어야함 int main(void) AAA a1=10; return 0;
55 explicit & mutable /* mutable.cpp */ #include<iostream> using std::cout; using std::endl; class AAA private: mutable int val1; int val2; public: void SetData(int a, int b) const val1=a; // val1이 mutable이므로 OK! val2=b; // Error! ; int main(void) AAA a1; a1.setdata(10, 20); return 0;