2014-09-12 6 views
1

void * pointer를 사용하여 하나의 전역 테이블에 다른 개체를 저장하려고합니다. 문제는 void * 객체를 다시 검색하는 방법입니다. 하나의 공통 기본 클래스 인 Object라고하면 Object *로 void * 포인터를 저장 한 다음 Object *로 다시 캐스트 할 수 있습니다. From Object * 특정 유형으로 더 캐스트 할 수 있습니다.다른 개체를 void *로 저장하고 void에서 캐스팅 *

class Object{}; 
class A : public Object{ virtual ~A()} 
class B : public A { } 
class C : public Object{ virtual ~C()} 
class D: public C{}; 

A* aObj = new B; 
void* v = static_cast<Object*>(aObj);  

// scenario 1, try to get as A* 
Object* obj = static_cast<Object*> (v); 
A* vaobj = dynamic_cast<A*> (obj); // ok 

// scenario 2, try to get it as C* 
Object* obj = static_cast<Object*> (v); 
C* caobj = dynamic_cast<C*> (obj); // ok, caObj will be null so I can throw exception if this happens 

나는 해결책 나는 하나의 공통 기본 클래스의 안전을 때 알지만, 문제는 모든 다른 유형을 제어하지 않기 때문에 내가 공통 기본 클래스를 가질 수 있으며, 파생 수 없습니다 그들로부터 객체. 나는 일반적인 기본 클래스가없는 코드 :

class A{ virtual ~A() }; class B : public A{}; 
class C{ virtual ~C() }; class D : public C{}; 

A* aObj = new B; 
void* v = dynamic_cast<void*>(aObj);// to actually store the address of B 

// scenario 1, try to retrieve object as A* 
A* aObj2 = static_cast<A*>(v); 
A* aa = dynamic_cast<A*> (aObj2); // aa should be non null 

// scenario 2, try to retrieve object as C* 
C* cObj = static_cast<C*>(v); 
C* cc = dynamic_cast<C*>(cObj); // cc should be null 

질문 :

시나리오 1 : 나는 B의 주소 (*하지 무효화 할 것을 dynamic_cast는)으로 무효 * 포인터를 저장합니다. 그렇다면 나는 원래 void * ptr에 B *로 객체를 저장했기 때문에 안전하지 않다는 것을 알고있는 A *로 static_cast를 수행하고 void *에서 동일한 유형의 포인터를 저장하고 검색해야한다는 것을 알고 있습니다. 그런 다음 dynamic_cast를 사용하여 객체를 실제로 확인합니다. 그래서 이것이 작동해야하고, dynamic_cast가 나에게 올바른 객체를 주어야합니까?

시나리오 2 : 은 동일하지만, 지금은 주먹 C의 * 다음 더 dynamic_casting, 나는 NULL을 얻어야한다이 시간에 static_casting하고, 저장된 객체가 실제로 무효가 * 거의이다 저장 B.

+1

나는 "이 나쁜 냄새"고 말할 것입니다. 즉, 다른 해결책을 생각해야 할 것입니다. 왜 테이블과 관련없는 객체를 저장해야합니까? 어쩌면 대신 래퍼 객체를 저장해야할까요? –

+0

아니요, 확실히 개체 포인터를 저장해야합니다. 그래서 몇 가지 해결책이 필요합니다. 일반적인 문제이지만 추측하기가 힘들어합니다. – user152508

+0

그렇다면 ptr! = NULL ...을 사용하면 가독성이 떨어집니다. 코드와 성능에 좋지 않습니다. 아마도 여러분은 실제 문제가 무엇인지를 설명 할 수 있습니다. 문제를 해결하려고하는 방법이 아닙니다. 잘못된 해결책이라고 확신 할 수 있습니다. (오, 그리고 'dynamic_cast'도 일반적으로 너무 느립니다!) –

답변

0

했다 원인 C++에서는 필요하지 않지만 C에서는 평범합니다. C++에는보다 안전하고 형식이 안전한 대안이 있습니다. 예를 들어 부스트를 사용할 수 있습니다. 아님?

+0

no는 boost :: any를 사용할 수 없습니다. boost :: any는 저장된 정확한 유형을 검색해야합니다. 파생 된 ptr가 저장되면 기본 클래스 ptr로 검색 할 수 없습니다. – user152508

0

많은 의견 작성자들이 이미 말했듯이 C++에 void *를 저장하는 것은 실제로 필요하지 않습니다. 저장하는 유형을 제어 할 수없는 경우 해당 유형의 컨테이너를 만드십시오. 그렇게하면 정의와 동작을 제어 할 수 있습니다 (원하는 경우 Object에서 파생시킵니다).

매우 거친 작업 예 :

#include <iostream> 
#include <string> 

using namespace std; 

class Object{ 
    public: 
    virtual ~Object(){}; 
}; 

template<typename T> 
class Container : public Object{ 
    T* v; 
    public: 
    Container(T* b):v(b){} 

    T* value(){ 
     return v; 
    } 

    void deleteContained(){ 
     delete v; 
    } 
}; 

class foo{ 
public: 
    virtual string say(){ 
     return "foo"; 
    } 
}; 
class bar: public foo{ 
public: 
    string say(){ 
     return "bar"; 
    } 
}; 

int main(){ 
    Object* o; 
    o = new Container<foo>(new bar); 

    Container<foo>* fooCon = dynamic_cast<Container<foo>*>(o); 
    foo* fooObj = fooCon->value(); 
    // Since you now have the object in a foo*, you can dynCast it to a bar* if you like. 
    bar* barObj = dynamic_cast<bar*>(fooObj); 

    // Cast to the wrong container type is NULL. 
    Container<int>* nullInt = dynamic_cast<Container<int>*>(o); 
    if(nullInt) 
     cout << "Cast Successful." << endl; 
    else 
     cout << "Cast failed." << endl; 

    // Both will print "bar", since "o" contains a bar object. 
    cout << fooObj->say() << endl; 
    cout << barObj->say() << endl; 

    ((Container<foo>*)o)->deleteContained(); 
    delete o; 
} 

출력 :

Cast failed. 
bar 
bar 
+0

가 닫았지만 상속을 고려하지 않았습니다. B가 A. Object * obj = new Container (B())에서 상속되면 B *를 A *로 변환하려고합니다. 그리고 나서 나중에 컨테이너 aObj = dynamic_cast > (obj); 그것은 실패 할 것이다 – user152508

+0

나는 본다. 나는 더 적합한 해결책을 제시하려고 노력할 것이다. –