ProgramingTip

클래스의 유형이 C ++의 특정 하위 클래스인지 어떻게 확인합니까?

bestdevel 2020. 12. 6. 21:54
반응형

클래스의 유형이 C ++의 특정 하위 클래스인지 어떻게 확인합니까?


나는 사용 라인을 따라 생각 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유형이 상속 계층 구조의 어디에서나 대상 유형을 포함하는지 확인할 수 있습니다 (예, and 에서 B상속하면를 직접 바꿀 수있는 잘 알려지지 않은 기능입니다 ). 개체의 정확한 유형을 결정할 수 있습니다. 그러나 둘 다 극도로 드물게 사용해야합니다. 이미 언급했듯이 동적 유형 식별은 디자인 결함을 나타 내기 때문에 항상 피해야합니다. (당신이 알고있는 경우 또한, 객체는 대상 유형의 확실히, 당신이 가진 내리 뜬을 할 수있다 . 이벤트 부스트 와 풀이 죽은을 할 것입니다 디버그 모드로, 그리고 릴리스 모드에서 단지를 사용합니다 ).ACA*C*typeid()static_castpolymorphic_downcastdynamic_castassertstatic_cast


C ++에서 객체의 유형을 절대 확인하고 싶지 않다는 데 동의하지 않습니다. 피할 수있는 그렇게해야한다는 것을 동의합니다. 어떤 상황에서도 절대 이렇게하지 말라고 말하는 것이 너무 멀리 가고 있습니다. 이것은 매우 많은 언어로 할 수 있으며 훨씬 더 쉽게 만들 수 있습니다. 예를 들어 Howard Pinsley는 C #에 대한 그의 게시물에서 방법을 보여줍니다.

Qt Framework로 많은 작업을 수행합니다. 일반적으로 나는 그들이 일하는 방식에 따라 내가하는 일을 모델링한다 (적어도 결혼식에서 작업 할 때). QObject 클래스는 모든 Qt 객체의 기본 클래스입니다. 이 클래스에는 빠른 하위 클래스 검사로 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!";

문제를 널리 이해했는지 모르겠습니다. 제 말로 다시 말씀 드리겠습니다.

문제 : 주어진 클래스 인지 확인 BD, D의 하위 클래스 인지 확인 (또는 그 반대 B?)

솔루션 : 템플릿 마법을 사용하십시오! 좋아, 진지하게 당신은 전설적인 C ++ 저자 인 Andrei Alexandrescu가 제작 한 훌륭한 템플릿 메타 프로그래밍 라이브러리 인 LOKI를보고보고합니다.

보다 구체적으로 로키를 다운로드 하고 TypeManip.h소스 코드에 헤더 포함 시킨 후 SuperSubclass다음과 같이 클래스 템플릿을 사용합니다.

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

에 문서 SuperSubClass<B,D>::value따르면가 B의 공용-based D이거나 BD동일한 유형의 별칭 이면 사실 입니다.

즉 하나 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를 사용하지 않는 한 템플릿을 사용하여 타임에만 수행 할 수 있습니다.

유형에 대한 정보를 포함하는 type_info 구조에 대한 포인터를 생성하는 typeid 함수를 사용할 수 있습니다.

Wikipedia 에서 읽기


C #에서는 다음과 같이 말할 수 있습니다.

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
    }
}

아래 코드는이를 수행하는 3 가지 방법을 보여줍니다.

  • 가상 기능
  • typeid
  • dynamic_cast
#include <iostream>
#include <typeinfo>
#include <typeindex>

enum class Type {Base, A, B};

class Base {
public:
    virtual ~Base() = default;
    virtual Type type() const {
        return Type::Base;
    }
};

class A : public Base {
    Type type() const override {
        return Type::A;
    }
};

class B : public Base {
    Type type() const override {
        return Type::B;
    }
};

int main()
{
    const char *typemsg;
    A a;
    B b;
    Base *base = &a;             // = &b;    !!!!!!!!!!!!!!!!!
    Base &bbb = *base;

    // below you can replace    base    with  &bbb    and get the same results

    // USING virtual function
    // ======================
    // classes need to be in your control
    switch(base->type()) {
    case Type::A:
        typemsg = "type A";
        break;
    case Type::B:
        typemsg = "type B";
        break;
    default:
        typemsg = "unknown";
    }
    std::cout << typemsg << std::endl;

    // USING typeid
    // ======================
    // needs RTTI. under gcc, avoid -fno-rtti
    std::type_index ti(typeid(*base));
    if (ti == std::type_index(typeid(A))) {
        typemsg = "type A";
    } else if (ti == std::type_index(typeid(B))) {
        typemsg = "type B";
    } else {
        typemsg = "unknown";
    }
    std::cout << typemsg << std::endl;

    // USING dynamic_cast
    // ======================
    // needs RTTI. under gcc, avoid -fno-rtti
    if (dynamic_cast</*const*/ A*>(base)) {
        typemsg = "type A";
    } else if (dynamic_cast</*const*/ B*>(base)) {
        typemsg = "type B";
    } else {
        typemsg = "unknown";
    }
    std::cout << typemsg << std::endl;
}

위의 프로그램은 다음을 인쇄합니다.

type A
type A
type A

참고 URL : https://stackoverflow.com/questions/307765/how-do-i-check-if-an-objects-type-is-a-particular-subclass-in-c

반응형