객체의 유형이 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;
}

답변

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

  • 가상 기능
  • 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

답변

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


답변

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

저는 Qt 프레임 워크로 많은 작업을합니다. 일반적으로 나는 그들이 일하는 방식에 따라 내가하는 일을 모델링한다 (적어도 그들의 프레임 워크에서 작업 할 때). 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를 살펴볼 필요가 있습니다.

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

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

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

즉 하나 D의 하위 클래스 B또는 D동일하다 B.

이게 도움이 되길 바란다.

편집하다:

의 평가 SuperSubClass<B,D>::value는를 사용하는 일부 메서드와 달리 컴파일 타임 에 발생 dynamic_cast하므로 런타임에이 시스템을 사용하는 데 따른 불이익이 없습니다.