문제

Ampess 2 인터페이스가있는 클래스가 있으며 1 클래스를 상속합니다. 따라서 일반적으로 다음과 같이 보입니다.

class T : public A, public IB, public IC {
};

코드에는 내가있는 코드가 있습니다. IB *, 그러나 실제로 사용할 수 있습니다 A *. 나는 역동적 인 캐스트가 이것을 원하기를 바랐다.

IB *b_ptr = new T; // it's really more complicated, but serves the example
A *a_ptr = dynamic_cast<A *>(b_ptr);

불행히도 이것은 작동하지 않습니다. 이 작업을 수행하는 적절한 방법이 있습니까? 아니면 주변의 작업을 구현해야합니까? 나는 둘 다 가지고 있다고 생각했다 IB 그리고 IC 사실상 상속 A, 그러나 IIRC는 지난번에 나는 그것을 바람직하지 않은 합병증이 있다고 시도했다.

이견있는 사람?

편집하다: 오 예, 이것은 플러그인 API의 일부이므로 불행히도 나는 직접 액세스 할 수 없습니다. T 내가 필요한 곳에 입력하십시오 A *. 내 예는 서로 옆에 있었지만 언급했듯이 더 복잡합니다. 기본적으로 2 개의 공유 라이브러리가 있습니다. T 그리고 T1 (내가있는 곳 IB *)는 플러그인 API를 구현하고 공유 라이브러리 내부에있는 클래스입니다.

설명 : 다음은 일반적인 플러그인의보다 구체적인 예입니다 (별도의 라이브러리에 있습니다).

plugin A:

class PluginA : public QObject, public PluginInterface, public OtherInterface {
};

플러그인 B :

class PluginB : public QObject, public PluginInterface {
    // in here, I have a PluginInterface *, but really could use a QObject *
    // unfortunately, PluginB has absolutely no knowledge of the "PluginA" type
    // it just so happens that my PluginInterface * pointer points to an object of type
    // PluginA.
};

편집하다: 문제는 Plugina와 PluginB가 다른 공유 라이브러리에 있다는 것입니다. 아마도 RTTI는 모듈 경계를 교차하지 않을 것입니다. 사람들의 예가 내 시험에서 잘 작동하는 것처럼 보이기 때문에 이것이 사실이라고 생각합니다. 구체적으로, 플러그인은 "nm"을하는 경우 "plugina 용 타입 인포"가 없습니다. 이것은 문제의 핵심 일 수 있습니다. 이 경우 가상 상속 또는 가상으로 단순히 작업해야합니다. cast_to_qobject() 내 인터페이스 중 하나에서 작동합니다.

도움이 되었습니까?

해결책 4

나는 마침내 그것을 알아 냈다. 다니엘 폴 그것의 "옆으로 맞았습니다 dybnamic_cast"허용되어야합니다. 내 문제는 내 코드가 공유 라이브러리와 관련되어 있기 때문입니다. Plugina의 TypeInfo는 PluginB에서 사용할 수 없었습니다. 내 솔루션은 효과적으로 추가하는 것이 었습니다. RTLD_NOW 그리고 RTLD_GLOBAL 내 부하 과정에

기술적으로 그것은 그랬습니다

loader.setLoadHints(QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint);

QT의 플러그인 시스템을 사용하고 있지만 동일한 차이가 있기 때문입니다. 이 플래그는로드 된 라이브러리의 모든 기호를 즉시 해결하고 다른 라이브러리로 볼 수 있습니다. 따라서 TypeInfo를 필요로하는 모든 사람이 사용할 수 있도록합니다. 그만큼 dynamic_cast 이 깃발이 마련되면 예상대로 작동했습니다.

다른 팁

각 클래스에는 하나 이상의 가상 방법이 있습니까? 그렇지 않다면, 당신의 문제가 있습니다. 각 클래스에 가상 파괴자를 추가하면 문제를 극복해야합니다.

다음은 나를 위해 행복하게 일했습니다.

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

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

class A
{
public:
    virtual ~A() {}
    void foo() { /* stick a breakpoint here to confirm that this is called */ }
};

class T : public A, public IB, public IC 
{
public:
    virtual ~T() {}
};


int main(void)
{
    IB *b_ptr = new T;
    A *a_ptr = dynamic_cast<A *>(b_ptr);
    a_ptr->foo();
    return 0;
}

편집하다:

모든 새로운 정보와 비정상적인 행동 (코드가 작동해야합니다!) 후에 다음과 같은 도움이됩니까? IObject라는 인터페이스를 소개 하고이 기본 클래스의 사본이 하나만 있는지 확인하기 위해 가상 상속을 사용했습니다. 이제 iobject에 캐스트 한 다음 A에 캐스트 할 수 있습니까?

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

class IC : virtual public IObject
{
public:
    virtual ~IC() {}
};

class IB : virtual public IObject
{
public:
    virtual ~IB() {}
};

class A : virtual public IObject
{
public:
    virtual ~A() {}
    void foo() { /* stick a breakpoint here to confirm that this is called */ }
};

class T : virtual public A, virtual public IB, virtual public IC
{
public:
    virtual ~T() {}
};


int main()
{
    IB *b_ptr = new T;
    A *a_ptr = dynamic_cast<A *>( dynamic_cast<IObject *>(b_ptr) );
    a_ptr->foo();
    return 0;
}

나는 그것이 올바른 솔루션이라고 제안하지는 않지만 무슨 일이 일어나고 있는지에 대한 정보를 제공 할 수 있습니다 ...

이 작업을 수행하는 적절한 방법이 있습니까? 아니면 주변의 작업을 구현해야합니까? 나는 IB와 IC를 모두 A에서 상속받는 것에 대해 생각했지만, IIRC는 지난번에 원치 않는 합병증이 있다고 시도했습니다.

그런 다음 IB와 IC의 정의가 귀하의 통제하에 있음을 알 수 있습니다.

COM 인터페이스가 Windows에서 작동하는 방식이 있습니다. 이것들은 당신이 원하는 일을합니다.

  • 한 인터페이스에서 다른 인터페이스로 캐스트합니다
  • 구현은 발신자에게 불투명합니다
  • 구현만이 어떤 인터페이스를 구현하는지 알고 있습니다

이렇게하면 (미리 테스트되지 않은 코드)와 같은 일을 할 수 있습니다 ...

interface IQueryInterface
{
  IQueryInterface* queryInterface(const Guid* interfaceId);
};

interface IB : public abstract IQueryInterface
{
  ...
};

interface IC : public abstract IQueryInterface
{
  ...
};

//within your implementation class
IQueryInterface* T::queryInterface(const Guid* interfaceId)
{
  if (matches(interfaceId,GUID_IB))
    return (IB*)this;
  if (matches(interfaceId,GUID_IC))
    return (IC*)this;
  if (matches(interfaceId,GUID_A))
    return (A*)this;
  return 0;
}

이것의 훨씬 간단하고 하드 코딩 된 버전은 다음과 같습니다.

class A; //forward reference
interface IB
{
  virtual A* castToA() { return 0; }
};
class T : public A, IB, IC
{
  virtual A* castToA() { return this; }
};

먼저 t*로 캐스트 한 다음 a로 캐스트합니다.

IB *b_ptr = new T; // it's really more complicated, but serves the example
A *a_ptr = dynamic_cast<T *>(b_ptr);

일반적으로 IB가 A에 캐스트 할 수 있어야한다면 IB는 A에서 상속해야합니다.

편집 : 방금 이것을 시도했는데 작동합니다. 기본 메소드를 컴파일 할 때 e는 알 수 없습니다.

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

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

A* GetA();

int main()
{
    C *y = dynamic_cast<C *>(GetA());
    if (y == NULL)
        cout << "Fail!";
    else
        cout << "Ok!";
}

struct E : public A, public C
{
}; 

A* GetA() { return new E(); }

나는 또한 최근에 같은 종류의 문제로 귀찮았습니다. 자세한 내용은 GCC의 FAQ 항목을 참조하십시오.

http://gcc.gnu.org/faq.html#dso

rtld_* 플래그로 dlopen을 지시하는 것 외에도이 문제의 일부 화신은 링커에 의해 해결 될 수 있습니다 (-e 및 -besymbolic 옵션을 참조하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top