2013-04-01 6 views
0

공통베이스에서 파생 된 객체 집합이 ApiObject입니다. 별도의 데이터 구조로 모든 ApiObject를 등록 할 수 있어야하지만 기본 클래스가 아닌 객체의 실제 주소를 가져야합니다. 다중 상속을 사용하고 있습니다.생성자 초기화 후

파생 된 개체의 주소를 알 수 없기 때문에 코드를 ApiObject 생성자에 개체를 등록 할 수 없습니다. 파생 클래스의 생성자에 넣을 수도 없습니다. 실제로 다른 파생 클래스를 구성하는지 여부를 알 수 없으므로 (예 : B 클래스가 A에서 상속되고 둘 다 구성 될 수 있음).

그래서 내가 볼 수있는 유일한 옵션은 명시 적으로 그러나

B* b = new B(...); 
RegisterObject(b); 

에서, 우리는 객체를 생성 할 때마다 등록 함수를 호출하는 것입니다 내가 가지고, 이것은 매우 좋은 해결책이 될 것 같지 않습니다 매번이 함수를 호출하는 것을 잊지 마십시오.

나는 왜 내가이 일을하는지 더 많은 내용을 설명해야한다고 생각합니다. 객체는 오버로드 된 new 연산자를 통해 생성되며 객체가 생성 된 컨텍스트 (Lua 상태)를 알 필요가 있습니다. 예 :

Foo* object = new(L) Foo(...); 
// Foo is derived from ApiObject, and we want ApiObject to have a reference to L 

현재는 다소 unelegant 방식으로 수행된다 - 새로운 오퍼레이터는 개체 유형을 설명하는 몇몇 추가 데이터와 함께 거기에 L 포인터를 객체 전에 추가 바이트를 할당 및 저장한다. 그런 다음 기본 클래스는 init 함수를 통해이 '메타 데이터'에 대한 포인터를받습니다.
그렇지 않으면 마음에 오는 첫 번째 사실은 가상 함수이지만 생성자에서 호출 할 수 없으므로 기본 ApiObject 포인터를 등록해야하지만 이후의 가상 함수 만 호출하면됩니다. 그게 내 현재 구현보다 더 예쁘지 않은지 모르겠다.

+0

실제 주소로 무엇을 하시겠습니까? –

+0

@JoachimPileborg "파생 된 개체와 기본 개체 모두에서 동일합니다."--- 아니요, 실제로는 아닙니다. –

+0

@JoachimPileborg 이것은 기본 클래스와 파생 클래스에서 동일한 실제 주소가 아니며 _Not_가됩니다. –

답변

0

CRTP 클래스에서 등록하려는 모든 개체를 추가로 추출 할 수 있습니다.

template<class T> 
struct registarar_t<T> 
{ 
    registarar_t() 
    { 
    register(derived()); 
    } 

    T* derieved() 
    { 
    return static_cast<T*>(this); 
    } 
} 

struct IWantToRegister : registrar_t<IWantToRegister>, ApiObject 
{ 
} 

는 또한, 주의 수, derived() 포인터를 잘하지만, 객체가 아직 내가 그 고급 아니에요,

+0

기술적으로'static_cast'는 정의되지 않은 동작입니다 (실패했다고는 상상할 수는 없지만). 기본 클래스가 가상 클래스 인 경우 불법입니다 (다중 상속이 관련된 경우가 많습니다). –

+0

@JamesKanze 왜 정의되지 않습니까? –

+0

이 경우, 내가 줄 수있는 유일한 대답은 " 표준에 나와 있기 때문에"입니다. 가상 파생이없는 경우 I 은 일을 쉽게 할 수없는 이유를 볼 수 없습니다. 가상 파생물이있는 경우 'static_cast'는 입니다. 그러나 §3.8/5는 명시 적으로 그것이 정의되지 않았다고 말합니다. . –

0

아마 kassak의 솔루션은 더 우아 (부모 생성자에 접근) 초기화되지 않습니다, RegisterObject에 필요한 유형은 무엇

#include <iostream> 
struct ApiObject; 
void registerObj(ApiObject *foo); 

struct ApiObject{ 
    public: 
     ApiObject(std::string n){ 
      name = n; 
      registerObj(this); 
     } 

     std::string name; 
}; 

void registerObj(ApiObject *foo){ 
    std::cout<<"register called on "<<foo->name<<"\n"; 
} 


struct A : public ApiObject{ 
    public: 
     A(std::string n) : ApiObject(n) { 
      std::cout<<"init A\n"; 
     } 
}; 

struct B : public ApiObject{ 
    public: 
    B(std::string n) : ApiObject(n) { 
     std::cout<<"init B\n"; 
    } 
}; 


int main(){ 
    B *b = new B("b obj"); 
    A *a = new A("a obj"); 

    delete b; 
    delete a; 
} 
2

나는 경우 :하지만이 같은 (등록 당신이 그것을 할 때마다 작성하지 않아도 생성자에서 호출 할 shoudl을 권 해드립니다 t가 Base*이면, 최종 계층에 관계없이 Base, 의 생성자에서 호출 할 수 있습니다. 다른 유형이 있으면 그 유형의 생성자에서 호출하려고합니다. 당신 do doBase, 에서 파생 된 모든 클래스에서 호출하고 싶지만 어떤 유형의 클래스에서 파생 된 클래스에 대해서만 호출 할 수 있습니다.

RegisterObject 경우는 Base* 소요되며, 발생 제일 먼저 당신이 그것을 통과 포인터가 Base*로 변환됩니다 당신은 파생 클래스에서 함수에서 호출. RegisterObject은 파생 개체에 대한 포인터를받지 않습니다. 은 파생 개체의 Base에만 있습니다.

0

기본 생성자에서 등록 함수를 호출 할 수 있습니다. 기본 소멸자를 가상으로 만듭니다. 주소는 기본 및 파생 클래스에 대해 동일합니다. 전체 개체가 생성되기 전에 포인터 주소를 사용하지 마십시오.

모든 개체가 완전히 만들어지면 포인터 주소는 가상 함수 또는 파생 클래스로 동적 캐스팅을 통해 안전하게 사용할 수 있습니다.