2016년 3월 9일 수요일

[c++] this 포인터와 Friend

This Pointer: 객체가 멤버함수를 호출할 때 자동으로 멤버함수에게 전달되는 포인터, 호출한 객체를 가리키는 포인터를 말한다. 
흔히 자기 참조 포인터(자기 자신을 가리킬 수 있는 포인터)라고 불리우며, 멤버 함수에게만 this pointer가 전달된다.(Friend 함수는 멤버 함수가 아니므로 this pointer가 전달되지 않는다. Static 함수도 마찬가지이다.) 아래의 예제를 보면 금방 감이 올것이다. 
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. class Person   
  5. {  
  6. public:  
  7.     Person* GetThis(){        
  8.         return this//this 포인터를 리턴.  
  9.     }  
  10. };  
  11.   
  12. int main()  
  13. {  
  14.     Person *p1 = new Person();  
  15.     cout<<"포인터 p1: "<<p1<<endl;  
  16.     cout<<"p1의 this: "<<p1->GetThis()<<endl<<endl;  
  17.   
  18.     Person *p2 = new Person();  
  19.     cout<<"포인터 p2: "<<p2<<endl;  
  20.     cout<<"p2의 this: "<<p2->GetThis()<<endl;  
  21.   
  22.     return 0;  
  23. }  

  결과를 보면 알 수 있듯이, This 포인터는 멤버 함수를 소유한 객체를 가리키고 있다. 다시 말해서 멤버 함수를 호출할 때 사용한 객체를 가리키고 있다. 그럼 이런 this pointer의 타입은 어떻게 되는것일까? 일단 객체를 가리키는 것이므로 Person 클래스의 포인터 타입이 여기서 this의 리턴 타입이라고 할 수 있다. (Person * 타입)


일반적으로 클래스의 비공개멤버(private)는 외부함수에서 접근할 수 없다. 해 갈 수 없다. private 변수, 함수는 멤버 함수에서만 접근이 가능하기 때문이다. 그런데 멤버함수가 아닌 외부함수에서 접근해야 할 경우가 발생될 수 있다. 
 friend 라는 문법 : 그런 경우 클래스에서 프렌드함수로 선언해 주면 외부함수이면서 클래스의 비공개 멤버에 접근할수 있는 권한을 갖게 된다.
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. class Counter  
  5. {  
  6. private:  
  7.     int val;  
  8.   
  9. public:  
  10.     Counter() {   
  11.         val=0;  
  12.     }  
  13.     void Print() const {  
  14.         cout<<val<<endl;  
  15.     }  
  16.           
  17.     friend void SetX(Counter& c, int val);  //friend 선언.  
  18. };  
  19.   
  20. void SetX(Counter& c, int val) // 전역함수.  
  21. {  
  22.     c.val=val;  
  23. }  
  24.   
  25. int main()  
  26. {  
  27.     Counter cnt;  
  28.     cnt.Print();  
  29.   
  30.     SetX(cnt, 2002);  
  31.     cnt.Print();  
  32.   
  33.     return 0;  
  34. }  
  1. #include <iostream>  
  2. using std::cout;  
  3. using std::endl;  
  4.   
  5. class AAA  
  6. {  
  7. private:  
  8.     int data;  
  9.     friend class BBB;  // class BBB를 friend로 선언함!  
  10. };  
  11.   
  12. class BBB  
  13. {  
  14. public:  
  15.     void SetData(AAA& aaa, int val){  
  16.         aaa.data=val; //class AAA의 private 영역 접근!  
  17.     }  
  18. };  
  19.   
  20. int main()  
  21. {  
  22.     AAA aaa;  
  23.     BBB bbb;  
  24.   
  25.     bbb.SetData(aaa, 10);  
  26.   
  27.     return 0;  
  28. }  

 위 두 예제를 보면 쓰는 용법에 대해서는 간단히 한눈에 알아 볼 수 있다. friend는 함수, 클래스에 적용해서 쓸 수 있다. friend가 가지는 특징을 살펴 보면 아래 4가지 정도로 요약 할 수 있다. 
 1. 클래스에 friend 키워드와 함께 원형을 명시 해야 한다. 
 2. 상속 되지 않는다. 
 3. friend 함수는 클래스의 멤버가 아니라 일반함수이다. (멤버 접근 연산자로 접근하지 않는다.)
 4. 보통 사용되는 곳은 연산자 중복 사용시, 하나의 함수에서 다른 클래스들의 비공개 멤버로 접근시 사용된다. (전방참조)

※ 전방참조(Forward Reference)  : 두개 이상의 클래스를 동시에 선언하는 것은 논리적으로 불가능하므로 컴파일러에게 미리 이 클래스가 있음을 알려주는 것

 보통 friend가 OOP(Object Oriented Programming)의 캡슐화와 정보은닉을 해친다는 이야기가 있지만, 대다수의 경우 friend는 멤버의 개수를 줄여줌으로서 캡슐화에 더 이로운 영향을 끼친다. (public 멤버가 적을수록 캡슐화가 좋아진다)  friend를 피하기 위해 인위적으로 public 멤버를 추가한다면 그것이 오히여 OOP에 악역향을 끼친다. 

댓글 없음:

댓글 쓰기

[Effective C++] 항목 30 : 인라인 함수는 미주알고주알 따져서 이해해 두자.

인라인 함수를 사용하면 컴파일러가 함수 본문에 대해 문맥별 최적화를 걸기가 용이해집니다. 인라인 함수의 아이디어는  함수 호출문을 그 함수의 본문으로 바꿔치기하자는 것  남발했다가는 코드의 크기가 커질 게 뻔하다. 인라인 함수로 부풀려진 ...