سؤال

كنت أفكر على طول خطوط باستخدام typeid() ولكن أنا لا أعرف كيف أن أسأل ما إذا كان هذا النوع هو فئة فرعية من فئة أخرى (والتي بالمناسبة هو ملخص)

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

المحلول

هل حقا لا ينبغي.إذا كان البرنامج يحتاج إلى معرفة أي صف هو كائن ، التي عادة ما يشير إلى خلل في التصميم.انظر إذا كان يمكنك الحصول على السلوك تريد استخدام وظائف افتراضية.أيضا ، على مزيد من المعلومات حول ما كنت تحاول القيام به من شأنه أن يساعد.

أنا على افتراض أن يكون لديك مثل هذا الوضع:

class Base;
class A : public Base {...};
class B : public Base {...};

void foo(Base *p)
{
  if(/* p is A */) /* do X */
  else /* do Y */
}

إذا كان هذا ما لديك ، ثم حاول أن تفعل شيئا من هذا القبيل:

class Base
{
  virtual void bar() = 0;
};

class A : public Base
{
  void bar() {/* do X */}
};

class B : public Base
{
  void bar() {/* do Y */}
};

void foo(Base *p)
{
  p->bar();
}

تحرير: لأن النقاش حول هذا الجواب لا تزال مستمرة بعد سنوات عديدة ، فكرت أن رمي في بعض المراجع.إذا كان لديك مؤشر أو الإشارة إلى قاعدة الطبقة ، و الرمز الخاص بك يحتاج إلى معرفة اشتقاق فئة من وجوه ، فإنه ينتهك Liskov مبدأ الإحلال. العم بوب يدعو هذا "لعنة على وجوه المنحى والتصميم".

نصائح أخرى

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

class D1: public Base {};

class D2: public Base {};

int main(int argc,char* argv[]);
{
  D1   d1;
  D2   d2;

  Base*  x = (argc > 2)?&d1:&d2;

  if (dynamic_cast<D2*>(x) == nullptr)
  {
    std::cout << "NOT A D2" << std::endl;
  }
  if (dynamic_cast<D1*>(x) == nullptr)
  {
    std::cout << "NOT A D1" << std::endl;
  }
}

ويمكنك أن تفعل ذلك مع dynamic_cast (على الأقل لأنواع متعددة الأشكال).

في الواقع، على الفكرة الثانية - لا يمكنك معرفة ما إذا كان هو على وجه التحديد نوع معين مع dynamic_cast - ولكن يمكن أن أقول لكم إذا كان هذا النوع أو أي فئة فرعية منها

template <class DstType, class SrcType>
bool IsType(const SrcType* src)
{
  return dynamic_cast<const DstType*>(src) != nullptr;
}

وdynamic_cast يمكن تحديد ما إذا كان نوع يحتوي على نوع الهدف في أي مكان في التسلسل الهرمي الميراث (نعم، انها سمة من سمات غير معروفة أنه إذا يرث B من A وC، أنها يمكن أن تتحول إلى A* مباشرة في C*). typeid() يمكن تحديد نوع الدقيق للكائن. ومع ذلك، هذه يجب على استخدامها لماما للغاية. وكما سبق ذكره، يجب عليك دائما أن تجنب تحديد نوع الديناميكي، لأنه يشير إلى وجود خلل في التصميم. (أيضا، إذا كنت تعرف الهدف من ذلك هو لعلى يقين من نوع الهدف، يمكنك القيام مسبل مع static_cast. دفعة يقدم polymorphic_downcast التي من شأنها أن تفعل مسبل مع dynamic_cast وassert في وضع التصحيح، وفي وضع الإفراج انها ستستخدم فقط وstatic_cast).

وأنا أختلف التي يجب أن لا تريد أن تحقق نوع الكائن في C ++. إذا كان يمكنك تجنب ذلك، أنا أوافق أن يجب. قائلا يجب NEVER قيام بذلك تحت أي ظرف من الظروف تسير بعيدا جدا بالرغم من ذلك. يمكنك القيام بذلك في عدد كبير من اللغات، وأنها يمكن أن تجعل حياتك أسهل كثيرا. هوارد Pinsley، على سبيل المثال، أظهر لنا كيف في منصبه في C #.

وأفعل الكثير من العمل مع الإطار كيو تي. بشكل عام، أنا نموذج ما أقوم به بعد الطريقة التي تفعل أشياء (على الأقل عندما كان يعمل في إطارها). الطبقة QObject هي الفئة الأساسية من كافة الكائنات كيو تي. تلك الفئة لديها isWidgetType وظائف () وisWindowType () كما شيك فرعية سريع. فلماذا لا تكون قادرة على التحقق الفئات المشتقة الخاصة بك، وهو مشابه في انها الطبيعة؟ وهنا تدور QObject الخروج من بعض هذه الوظائف الأخرى:

class MyQObject : public QObject
{
public:
    MyQObject( QObject *parent = 0 ) : QObject( parent ){}
    ~MyQObject(){}

    static bool isThisType( const QObject *qObj )
    { return ( dynamic_cast<const MyQObject*>(qObj) != NULL ); }
};

وبعد ذلك عندما يتم تمرير حول مؤشر إلى QObject، يمكنك معرفة ما اذا كان يشير إلى فئة مشتقة عن طريق استدعاء الدالة عضو ثابت:

if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!";

أنا لا أعرف ما إذا كنت أفهم مشكلتك بشكل صحيح, لذلك اسمحوا لي أن أكرر ذلك في كلماتي...

المشكلة:إعطاء دروس B و D, لتحديد ما إذا كان D هو فئة فرعية من B (أو العكس بالعكس؟)

الحل:استخدام بعض قالب السحر!حسنا حقا تحتاج إلى أن تأخذ نظرة على لوكي, قالب ممتاز الفوقية مكتبة البرمجة التي تنتجها اسطوري C++ المؤلف اندريه Alexandrescu.

وبشكل أكثر تحديدا, تحميل لوكي وتشمل رأس TypeManip.h من ذلك في التعليمات البرمجية المصدر الخاصة بك ثم استخدام SuperSubclass قالب فئة على النحو التالي:

if(SuperSubClass<B,D>::value)
{
...
}

وفقا الوثائق ، SuperSubClass<B,D>::value سوف يكون صحيحا إذا B هو الجمهور قاعدة D, أو إذا B و D هي الأسماء المستعارة من نفس النوع.

أيإما D هو فئة فرعية من B أو D هو نفس B.

آمل أن يساعد هذا.

تحرير:

يرجى ملاحظة تقييم SuperSubClass<B,D>::value يحدث في وقت الترجمة على عكس بعض الأساليب التي تستخدم dynamic_cast, ومن ثم لا يوجد عقوبة استخدام هذا النظام في وقت التشغيل.

#include <stdio.h>
#include <iostream.h>

class Base
{
  public: virtual ~Base() {}

  template<typename T>
  bool isA() {
    return (dynamic_cast<T*>(this) != NULL);
  }
};

class D1: public Base {};
class D2: public Base {};
class D22: public D2 {};

int main(int argc,char* argv[]);
{
  D1*   d1  = new D1();
  D2*   d2  = new D2();
  D22*  d22 = new D22();

  Base*  x = d22;

  if( x->isA<D22>() )
  {
    std::cout << "IS A D22" << std::endl;
  }
  if( x->isA<D2>() )
  {
    std::cout << "IS A D2" << std::endl;
  }
  if( x->isA<D1>() )
  {
    std::cout << "IS A D1" << std::endl;
  }
  if(x->isA<Base>() )
  {
    std::cout << "IS A Base" << std::endl;
  }
}

والنتيجة:

IS A D22
IS A D2
IS A Base

ويمكنك القيام بذلك إلا أنه في وقت الترجمة باستخدام القوالب، إلا إذا كنت تستخدم RTTI.

وهذا يتيح لك استخدام وظيفة typeid التي سوف تسفر مؤشر إلى بنية type_info الذي يحتوي على معلومات حول نوع.

وتقرأ على أنها في ويكيبيديا

في ج # يمكنك ببساطة أن نقول:

if (myObj is Car) {

}
<اقتباس فقرة>   

وأنا أفكر على غرار باستخدام typeid() ...

حسنا، نعم، يمكن أن يتم ذلك من خلال مقارنة: typeid().name(). وإذا أخذنا الحالة الموصوفة سابقا، حيث:

class Base;
class A : public Base {...};
class B : public Base {...};

void foo(Base *p)
{
  if(/* p is A */) /* do X */
  else /* do Y */
}

وهناك إمكانية تنفيذ foo(Base *p) ستكون كما يلي:

#include <typeinfo>

void foo(Base *p)
{
    if(typeid(*p) == typeid(A))
    {
        // the pointer is pointing to the derived class A
    }  
    else if (typeid(*p).name() == typeid(B).name()) 
    {
        // the pointer is pointing to the derived class B
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top