سؤال

لدي فصل يحتوي على واجهتين ويرث فئة واحدة.لذا، بشكل عام يبدو الأمر كما يلي:

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 في المرة الأخيرة حاولت أن هناك بعض التعقيدات التي جعلت الأمر غير مرغوب فيه.

أي أفكار؟

يحرر:أوه نعم، هذا جزء من واجهة برمجة تطبيقات البرنامج الإضافي، لذا لسوء الحظ ليس لدي إمكانية الوصول المباشر إلى T اكتب حيث أحتاج إلى A *.المثال الخاص بي يقع بجوار بعضها البعض، ولكن كما ذكرنا، الأمر أكثر تعقيدًا.في الأساس لدي مكتبتان مشتركتان. T و T1 (حيث لدي IB *) كلاهما فئتان تنفذان واجهة برمجة تطبيقات البرنامج الإضافي وهما داخليتان للمكتبات المشتركة.

للتوضيح:فيما يلي مثال أكثر تحديدًا للمكونات الإضافية النموذجية (وهي موجودة في مكتبات منفصلة):

البرنامج المساعد أ:

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

البرنامج المساعد ب:

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 حدود الوحدة.أعتقد أن هذا قد يكون هو الحال لأن أمثلة الأشخاص تبدو وكأنها تعمل بشكل جيد في اختباراتي.على وجه التحديد، لا يحتوي pluginB على "typeinfo for PluginA" إذا قمت بعمل "nm" عليه.وقد يكون هذا هو جوهر القضية.إذا كان هذا هو الحال، فسوف يتعين علي ببساطة التغلب على المشكلة إما عن طريق الميراث الافتراضي أو الظاهري cast_to_qobject() وظيفة في واحدة من واجهاتي.

هل كانت مفيدة؟

المحلول 4

وأخيرا حظيت بها، دانيال Paull كان صحيحا في أن "جانبية ينبغي أن يسمح dybnamic_cast ". كانت مشكلتي لقانون بلدي هي التي تنطوي المكتبات المشتركة. كان typeinfo من PluginA غير متوفر في PluginB. وكان بلدي الحل لإضافة فعال RTLD_NOW وRTLD_GLOBAL إلى عملية تحميل بلدي

وتقنيا كان

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

ولأنني أستخدم نظام المساعد كيو تي ولكن الفرق نفسه. هذه العلامات تجبر كل الرموز من المكتبات تحميل لحلها فورا، وتكون مرئية إلى مكتبات أخرى. مما يجعل بالتالي 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 بشكل عام يجب أن يكون castable إلى 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(); }

ولقد تم مؤخرا أيضا ازعجت مع نفس النوع من المشاكل. لمزيد من المعلومات، راجع التعليمات دخول دول مجلس التعاون الخليجي:

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

وإلى جانب تعليمات dlopen مع RTLD_ * الأعلام وبعض التجسيد لهذه المشكلة يمكن حلها عن طريق رابط كذلك، راجع خيارات -E و-Bsymbolic لها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top