프록시(Proxy) 클래스편집하기 Proxy Object : 객체를 대신하는 다른 객체를 두는 방법
•대리자(surrogate)라고도 알려짐
Operator[]의 읽기/쓰기 구분 방법
프록시 클래스의 대표적인 응용 사례임.
•읽기동작을 우항값(rvalue) 연산, 쓰기동작을 좌항값(lvalue) 연산이라 함.
operator[]의 결과값이 사용되기까지 좌항값/우항값 연산을 늦추면 읽기와 쓰기를 다르게 처리할 수 있음. - 지연평가(lazy evaluation)
•프록시를 생성, 프록시가 대신할 문자열 내의 문자 지정
•이 프록시를 대입 연산의 대상(target)으로 사용
프록시가 대신하는 문자에 대해 직접 대입 연산을 수행, 이러게 사용되는 프록시는 operator[]를 호출 한 문자열에 대한 좌항값을 대신함.
•이 외의 경우에 사용되는 프록시
이렇게 사용되는 프록시는 operator[]호추란 문자열에 대한 우항값을 대신함.
class String
{
...
public:
class CharProxy
{
public:
CharProxy(String& str, int index);
CharProxy& operator=(const CharProxy& rhs);
CharProxy& operator=(char c);
operator char() const; // 암시적 캐스팅이라거
...
int NeedA() const;
};
friend class CharProxy; // String객체의 buffer에 접근해야되기 때문에 후렌드
...
int NeedA() const;
};
그래서 CharProxy 클래스를 만들어따.
String s1 = "A C8";
std::cout << s1[2];
CharProxy 의 암시적 타입변환이 어루어져 출력됨.
s1[0] = s2[2];
CharProxy에도 operator[]가 필요함.
프록시 클래스라고 능사는 아니다
String s1 = "A E C8";
char * = &s1[1];
이런 경우 CharProxy에 주소 연산자(address of, & 연산자)를 오버로딩 해야함.
++, +=, --, -= 등을 작동시키려고 한다면 마찬가지로 연산자 오버로딩을 해야함.
String s1 = "A 2C8";
s1.NeedA();
프록시를 통해 원래 객체의 맴버 함수를 호출하려고 할 때도 마찬가지의 문제가 발생함.
프록시가 원래 객체처럼 동작하게 하려면 원래 객체에 적용할 수 있는 함수를 모조리 오버로딩해서 프록시에 적용되게 해야함.
void swap(char& a, char& b);
String s = "AM 2:24";
swap(s[2], s[4]);
비상수 객체 참조자를 받아들이는 함수의 매개 변수로 프록시를 넘길 경우도 원래 객체를 대신할 수 없음.
CharProxy에 char&에 대한 암시적 변환 함수가 없음.
임시 객체를 비상수 참조 매개변수로 넘길 수 없음 - 항목 19 참조
매개변수의 타입을 그 함수가 요구하는 타입으로 바굴 때 컴파일러가 호출할 수 있는 사용자 정의 변환 함수는 최대 하나임.
따라서, 원래의 객체를 넘기면 컴파일이 잘 되던 함수에 프록시를 넘기면 컴파일이 안될 수 있음.
총정리
프록시 클래스는 어떤 객체를 대신하여 동작하는 장치임.
프록시 객체는 임시 객체이기 때문에, 객체 생성 및 소멸 과정이 저절로 수반됨.
프록시 클래스를 사용한 소프트웨어 시스템은 그렇지 않은 것보다 더 복잡함.
원래의 객체를 사용하는 클래스를 프록시를 사용하는 버전으로 바꿀 때에는 그 클래스의 의미구조도 어쩔 수 없이 바꾸어야 하는 경우도 더러 있다.
프록시 객체는 대개 원리 객체와 약간 다른 동작패턴을 보이기 때문이다.
이 때문에 시스템 설계 단계에서 프록시를 멀리하기도 한다. <- 영형이 줄친 부분
하지만 프록시를 사용자에게까지 드러내는 동작이 필요한 경우는 별로 많지 않다. <- 다음 문장도 신경 써줬음 조케따
tag : proxy , Proxy , ProxyObject , proxyobject , 객체 , 프록시 객체 , UML , uml