C++로 특정 Class를 등록하고 필요할때 마다 사용하고 싶은데..
글쓴이: fleabane / 작성시간: 화, 2011/08/02 - 11:25오후
안녕하세요 C++ 초보입니다.
프로그램을 짜다가 특정 Class를 어딘가에 등록을 하여 필요 할때마다
끄내쓰거나 바꿔쓰거나 하고 싶은 마음에 아래와 같이 구현을 해보았습니다.
//Interface Class class IDev { public : IDev(); virtual ~IDev(); virtual void executeA() = 0; virtual void executeB() = 0; }
그래서 이놈을 상속 받는 TestDevice를 구현했습니다
//Test Device class CTestDevice : public IDev { public : CTestDevice(); virtual ~CTestDevice(); virtual void executeA() { printf("Execute A\"); } virtual void executeB() { printf("Execute B\"); } }
뭐 딱 보면 아시겠지만 거의 동일한 기능을 가진 Device를 Class로 각각 구현을 하여 동일한
인터페이스를 가지고 갈려고 하는 것입니다.
그래서 이놈을 등록 시킬 수 있는 Class 하나를 만들어서
class CDevRegsiter { private : static IDev* m_pDevice; public : static void regsiterDevice( IDev* pDev ) { if( m_pDevice ) { m_pDevice = new??????????? /*이부분을 어떻게 하면 될지???*/ } } static IDev* getDevice() { return m_pDevice; } } void main() { CTestDevice testDev; CDevRegsiter::regsiterDevice( &testDev ); CDevRegsiter::getDevice()->executeA(); }
위에 CDevRegsiter::regsiterDevice()안에 ?????? 한부분이 고민입니다.
그냥 m_pDevice = pDev 해도 뭐 컴파일 에러는 당연히 안나더군요.
하지만 결국 그렇게 되면 CDevRegsiter::m_pDevice는 나중에 쓰레기 값이 들어가기 때문에 안될거 같고
main에서
CTestDevice gTestDev; void main() { CDevRegsiter::regsiterDevice( &gTestDev ); //이거는 밑에것이랑 같아서 의미 없다고 생각됨 CDevRegsiter::getDevice()->executeA(); gTestDev.executeA(); }
이렇게 하자니 그럼 굳이 Interface class를 만들 필요도 없을거 같고..
파리마터로 들어온 Class현재의 바인딩(이 표현이 맞는지 모르겠습니다)된 class가 뭔지 알수 있는 방법은 없을까요?
Forums:
void regsiterDevice( IDev*
void regsiterDevice( IDev* pDev )에서
pDev가 IDev에서 상속된 놈인지 검사해 주는 걸 이미 하고 있으며...
그냥 m_pDevice = pDev 하면 될 듯...
결국 그렇게 되면 CDevRegsiter::m_pDevice는 나중에 쓰레기 값이 들어가기 때문?????? 이게 무슨 말인지????
쓰레기 값이 들어간다는게
예를 들어
이런식으로 구현을 했을때에는 CDevRegsiter::m_pDevice는 setDevice()안의 로컬 testDev의 주소를 대입했기 때문에
runDevice()에서 사용할때에는 해당 주소에 결국 쓰레기 값만 있게 될거란 설명이었습니다.
그럼 이부분에 대입을 할때 operator= 을 overloading을 해서 하면 문제가 해결될까요?
IDev = TestDev꼴이 되는거라서 이게 가능한지 헛갈리네요.
인자로 넘겨주는 인스턴스가 소멸되었을때 얘기라면
인자로 넘겨주는 인스턴스가 소멸되었을때 얘기라면 대입이 아니라 복사를 하면 될듯...
C++의 클래스는 스스로를 서술하는 기능을 포함하지
C++의 클래스는 스스로를 서술하는 기능을 포함하지 않습니다.
표준에서 보장하는 것은 상속관계를 dynamic_cast로 확인할수 있는 정도입니다.
말씀하신대로 등록하고 싶은 것은 클래스이므로, 암만 객체를 넘겨줘봤자 소용이 없습니다.
클래스에 대한 정보를 넘겨야지요.
클래스를 등록해서 어떤 것을 가능하게 할 것인지 구체적으로 밝히지 않으셨으므로 구체적인 답변은 불가능합니다만,
클래스에 대한 정보를 담은 객체(메타객체)를 넘겨주거나, 객체 자체에 메타 객체를 포함시켜야 겠지요.
예를 들어 이름만 알면 된다면,
class MetaDevice {
public:
virtual std::string name() const = 0;
};
이런 클래스를 만들어서, 이걸 상속 받아서 이걸 넣어줘야겠지요.
class MetaDeviceA : public MetaDevice {
public:
virtual std::string name() const {return "device a";}
};
이런 메타객체는 보통 여러개의 객체(이경우라면 많은 device a 객체들)에 대해서 하나만 필요하므로, 싱글톤으로 만드는 것도 생각해 볼수 있을듯합니다.
런타임에 등록된 클래스의 생성이 필요하다면 팩토리 패턴을 이용할수도 있겠구요.
위 경우는 void regsiterDevice(
위 경우는 void regsiterDevice( IDev* pDev )라고 할때
pDev를 넘겨주면 IDev *인지 타입검사를 하면서 상속관계가 검사됩니다.
아니면 IDev *로 캐스팅이 안되면 컴파일 오류...
필요이상으로 어렵게 생각하는듯...
자세한 답변 감사드립니다.
제가 설명이 좀 부족했던 부분이 있군요.
예를 좀 정확히 들어서 설명을 드릴테니 아시는 한도내에서 답변 해주시면 감사하겠습니다.
말씀하신데로 거의 동일한 기능을 수행하는 Device를 필요한 상황에 따라 런타임에 등록을 하고 해지를 하며 사용할려고
생각중입니다.
그 Device를 예를 들어 뭐 마우스의 클릭과 관련된 디바이스라고 하면 사용자가 보기에는 마우스는
Left/Right Click의 동일한 기능만 가지고 있으나 그 Left Click/ Right Click을 동작하는 방법은 내부적으로
차이가 있을 수 있다는 전제로 구상을 하였습니다.
사용자는 Mouse인스턴스의 Left/Right Click을 사용하지 그 내부 구조는 모르고 싶다는 전제이고요.
이렇게 되었을때
결과적으로 Device는 동일한 method를 제공하지만 각 Device별로 동작하는 방식이 다르고 사용하는 Data와 private 맴버가
다른 상태인 상황에서(위에는 간단하게 char/int 하나씩 했지만 실제로는 더 큰 Data Table을 사용하여 진행이될때)
register내부에서 '='연산(Deep Copy)가 가능한지가 궁금합니다.
지금 operator=을 overloading해보고는 있는데 컴파일 에러 잡고 있는 중이라서 아직 결과는 안나온 상태입니다.
무슨 의도이신지 잘 모르겠습니다. 앞의 설명보다,
무슨 의도이신지 잘 모르겠습니다.
앞의 설명보다, 저렇게 등록한 걸로 무엇을 할려고 하시는 것인지를 구체적으로 보여주시는게 더 알기 쉬울 것같습니다.
적으신걸 보니 또 제가 앞에 적은거랑은다른 의도이신것도 같고...
아무튼 맨뒤에 질문하신것에만 답변하자면,
일단 overloading은 컴파일타임에 결정되는 것이므로 런타임에 동적바인딩되게 할수는 없습니다(이게 되게 하는게 overriding이지요).
더불어서 IMouse *operator = (IMouse *)와 IMouse &operator = (const IMouse &)는 다른 함수입니다.
다형성과 함께 deep copy가 필요하다면 copy 함수를 가상함수로 넣어두면 되겠지요.
음
참 머리속에 있는걸 글로 풀어 쓰는게 쉬운게 아닌군요 ㅎㅎ
위와 같이 mouse class가 있을때
대충 시나리오는 이렇습니다.
'Process A'에서 지속적으로 현재 마우스 타입을 검사하며 마우스 타입이 변경이 되었을때
해당 정보를 CDevRegsiter에 등록을 시켜주면
'Process B'에서 트리거 신호를 기다렸다가 트리거 신호가 들어오면 현재 등록되어 있는 마우스의
left/right 클릭을 실행하는 것이죠.
그래서 CDevRegister Class에 현재 정보를 저장하려고 IMouse* m_pMouse맴버 변수를 static으로 해두었습니다.
IMouse m_mouse로 하고 싶다만 virtual pure class라 그렇게는 불가능하고..
그래서 regsiterDevice( IMouse* pDev )에는 CCharMouse가 들어올수도 있고 CIntMouse가 들어올 수도 있는 상황인데
에 대한 의문이 생긴거고요.
마우스 객체를 넘겨주고 해제 하지말고,
마우스 객체를 넘겨주고 해제 하지말고, CDevRegister 클래스가 필요없어진 마우스 객체의 메모리를 해제하게 하면 되겠네요.
IMouse *CDeveRegister::m_pMouse = 0;
void CDevRegister::registerDevice(...) {
if (m_pMouse) {
delete m_pMouse;
m_pMouse = 0;
}
m_pMouse = pDev;
}
댓글 달기