2010-04-08 4 views
0

C++에서 흥미로운 문제가 있었지만 아키텍처에 대한 자세한 내용이었습니다.C++ 동적 유형 구성 및 검색

는, 예를 들어 일부 특성 (MIX-클래스)를 설명하는 많은 (10, 20, 40 등)의 클래스가있다 :

struct Base { virtual ~Base() {} }; 

struct A : virtual public Base { int size; }; 
struct B : virtual public Base { float x, y; }; 
struct C : virtual public Base { bool some_bool_state; }; 
struct D : virtual public Base { string str; } 
// .... 

기본 모듈 선언하고 단순 단지 함수 (기능 수출 수업이없는 선언) :

// .h file 
void operate(Base *pBase); 

// .cpp file 
void operate(Base *pBase) 
{ 
    // .... 
} 

다른 모듈은 다음과 같은 코드를 가질 수 있습니다

#include "mixing.h" 
#include "primary.h" 

class obj1_t : public A, public C, public D {}; 
class obj2_t : public B, public D {}; 

// ... 
void Pass() 
{ 
    obj1_t obj1; 
    obj2_t obj2; 

    operate(&obj1); 
    operate(&obj2); 
} 

질문은 operate()에있는 주어진 객체의 실제 유형이 dynamic_cast 및 클래스 (상수 등)에있는 유형 정보를 사용하지 않고 어떻게되는지를 아는가? operate() 함수는 작은 시간 간격으로 많은 수의 객체와 함께 사용되며 dynamic_cast은 너무 느리고 상수 (enum obj_type { ... })를 포함하고 싶지 않습니다. 이는 OOP 방식이 아니기 때문입니다.

// module operate.cpp 

void some_operate(Base *pBase) 
{ 
    processA(pBase); 
    processB(pBase); 
} 

void processA(A *pA) 
{ 
} 

void processB(B *pB) 
{ 
} 

이 함수에 직접 pBase을 전달할 수 없습니다. 그리고 가능한 모든 클래스 조합을 가질 수는 없습니다. 왜냐하면 새로운 헤더 파일을 포함 시켜서 새로운 클래스를 추가 할 수 있기 때문입니다. 마음에 온

하나의 솔루션으로, 편집기에서 나는 복합 용기 사용할 수 있습니다

struct CompositeObject 
{ 
    vector<Base *pBase> parts; 
}; 

을하지만 편집기는 시간 최적화를 필요로하지 않는다 및 부품이 정확한 유형을 결정하는 dynamic_cast를 사용할 수 있습니다. operate()에서이 솔루션을 사용할 수 없습니다.

따라서이 문제를 해결하기 위해 dynamic_cast을 입력하고 정보를 입력하지 않아도됩니까? 아니면 다른 아키텍처를 사용해야합니까?

+5

왜 실제 유형을 알아야합니까? 가상 기능을 사용할 수없는 이유는 무엇입니까? –

+0

상수를 사용하여 가능한 모든 방법 dynamic_cast, RTTI를 제한했습니다. 또는 "string typeName"을 저장하면 Neil이 대답 한 옵션 중 하나 인 "another architecture"가 남았습니다. – dicaprio

+0

> 가상 기능을 사용할 수없는 이유는 무엇입니까? 이 mixin 클래스에 대한 공통 인터페이스가 없기 때문입니다. – KneLL

답변

2

실제 문제는 달성하려는 내용입니다.

당신이 같은 하시겠습니까 :

void operate(A-B&) { operateA(); operateB(); } 

// OR 

void operate(A-B&) { operateAB(); } 

당신이 각 하위 (독립적으로)에 대해 작업을 적용 할 할, 또는 구성 요소의 조합에 따라 작업을 적용 할 수하고자 할 (훨씬 열심히).

여기서는 첫 번째 방법을 사용합니다.

1. 가상?

class Base { public: virtual void operate() = 0; }; 

class A: virtual public Base { public virtual void operate() = 0; }; 
void A::operate() { ++size; } // yes, it's possible to define a pure virtual 

class obj1_t: public A, public B 
{ 
public: 
    virtual void operate() { A::operate(); B::operate(); } 
}; 

더 많은 작업이 필요합니다. 특히 나는 반복을 많이 좋아하지 않는다. 그러나 이것이 _vtable에 대한 하나의 호출이므로 가장 빠른 솔루션 중 하나 여야합니다!

2. 아마 여기에 더 자연스러운 일이 될 것입니다

복합 패턴.

C++에서 패턴의 템플릿 버전을 완벽하게 사용할 수 있습니다!

template <class T1, class T2, class T3> 
class BaseT: public Base, private T1, private T2, private T3 
{ 
public: 
    void operate() { T1::operate(); T2::operate(); T3::operate(); } 
}; 

class obj1_t: public BaseT<A,B,C> {}; 

장점 :

  • 자신을 반복 할 필요가 더 이상! (... 드러내는 가변) 한번에 그래서 더욱 효율적
  • A, BC 임의의 유형이 될 수 있기 전에, 그들이 상속하지 않도록
  • 단 1 가상 전화, 더 이상 가상 상속을 operate 쓰기 모든
  • 편집A, BCoperate 방법에 Base에서이 virtual
,369 아니라고 지금은 인라인 될 수 있습니다

단점 :

가변성 템플릿에 대한 액세스 권한이 아직없는 경우 프레임 워크에서 더 많은 작업이 이루어 지지만 몇 가지 라인에서 실행 가능합니다.

+0

+1 그리고 variadic 템플릿 구현이없는 경우 상용구의 상당 부분을 쓰는 것을 피하기 위해 boost :: preprocessor를 살펴볼 수 있습니다. –

+0

필자는 그것을 적어 두려고했지만, GMan은 전 처리기 미치광이라는 표를 던져주었습니다 : p –

+0

응답을 보내 주셔서 감사합니다. 그러나 믹스 인 클래스에는 공용 인터페이스가 없다고 썼습니다. 그리고 Composite에 대해서는 알고 있지만, final 타입은 mixin 클래스에서 파생 될 수 있기 때문에 사용할 수는 없습니다. 나는 단지 복합 객체를 단순한 것으로 사용하는 방법을 원한다. 구조체 TransA { void operator() (A * pa) {pa-> size - = 10; } }; 공극 업데이트 (B의 *를 PB, POINT2의 P) {// ...} 공극 캡 (D에 *를 PD) {// ...} 공극 F (벡터 O) { 의 for_each (O. begin(), o.end(), TransA()); 모자 (* o.begin()); }; Visitor 패턴을 사용할 수는 있지만 현재 20 개 이상의 클래스가 있으며 함수의 수가 너무 많습니다. – KneLL

2

가장 먼저 생각 나는 것은 실제로 달성하고자하는 것을 묻는 것입니다. 그러나 두 번째 생각은 방문자 패턴을 사용할 수 있다는 것입니다. 런타임 형식 정보는 암시 적으로 계층 구조의 어느 시점에서 accept 메서드의 최종 재정의 자인지를 결정하는 데 사용되지만 명시 적으로 해당 정보를 사용하지 않습니다 (코드에 dynamic_cast, type_info, 상수가 표시되지 않음)

다시 한번, 나의 첫 번째 생각이 돌아옵니다 ... 건축의 적합성에 대해 묻기 때문에, 당신이 정말로 달성하고 싶은 것은 무엇입니까? - 문제에 대한 지식이 없으면 일반 답변 만 찾을 수 있습니다.

+0

설명하려고합니다. 이미징 및 RPG 게임과 그 안에 많은 것들. 단순한 종류의 물건에는 무기, 갑옷, 쓰레기, 빛, 물약, 스크롤, 책 등의 유형이 있습니다. 각 유형은 혼합 수업으로 구현됩니다. 그러나 게임의 많은 항목은 하나 이상의 유형을 가질 수 있습니다. 예를 들어, 작은 항목 (무기, 조명, 컨테이너)에 대해 빛과 숨겨진 장소가있는 큰 도끼 일 수 있습니다. 벨트에 붙일 수있는 스킨 백으로 장갑 갑옷처럼 행동 할 수 있고 용기처럼 사용할 수 있습니다. 앱의 다른 장소에서 나는 단순한 것과 같은 복합 오브젝트로 작업하기를 원합니다. – KneLL

1

일반적인 객체 지향적 인 방법은 기본 클래스에 operate()에서 호출되는 (순수한) 가상 함수를 갖는 것입니다.이 함수는 파생 클래스에서 재정의되어 해당 파생 클래스에 특정한 코드를 실행합니다.

+0

내가 제안한 것보다 내베이스의 각 믹스 인 클래스의 모든 기능 프로토 타입이 있습니다. 지금은 20 개의 클래스에서 약 55 개의 함수입니다. 내 기본 수업에 너무 큰 Facade를 갖고 싶지 않아. 그리고 저는 기본 클래스가 아이들에 관해서는 안된다고 생각합니다. – KneLL

+0

템플릿을 사용하지 않는 한 C++에서이를 수행하는 유일한 방법입니다. 'P' 객체가'Q' 객체를 처리해야하지만 실제로'B'라는 기본 클래스를 통해'Q'에 대한 정보 만 가지고 있다면'B'는'P'가'Q'에서 접근 할 필요가있는 것을 정의해야합니다 'P'는'Q'의 선언문을 전혀 모릅니다). 그것은'operational()'함수로 제한 될 수 있습니다. –

0

문제는 두 개 이상의 객체 유형에 따라 수행 할 작업을 결정하려는 것입니다. 가상 함수는 하나의 객체 (. 또는 ->의 왼쪽 객체)에 대해서만이 작업을 수행합니다. 하나 이상의 개체에 대해 이렇게하는 것은 multiple dispatch (두 개체의 경우 double dispatch이라고도 함)이며 C++에서는이 문제를 처리 할 기본 제공 기능이 없습니다.

이중 배송을 특히 visitor pattern에서 확인하십시오.