클래스의 유형이 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
상속하면를 로 직접 바꿀 수있는 잘 알려지지 않은 기능입니다 ). 개체의 정확한 유형을 결정할 수 있습니다. 그러나 둘 다 극도로 드물게 사용해야합니다. 이미 언급했듯이 동적 유형 식별은 디자인 결함을 나타 내기 때문에 항상 피해야합니다. (당신이 알고있는 경우 또한, 객체는 대상 유형의 확실히, 당신이 가진 내리 뜬을 할 수있다 . 이벤트 부스트 와 풀이 죽은을 할 것입니다 및 디버그 모드로, 그리고 릴리스 모드에서 단지를 사용합니다 ).A
C
A*
C*
typeid()
static_cast
polymorphic_downcast
dynamic_cast
assert
static_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!";
문제를 널리 이해했는지 모르겠습니다. 제 말로 다시 말씀 드리겠습니다.
문제 : 주어진 클래스 인지 확인 B
및 D
, D
의 하위 클래스 인지 확인 (또는 그 반대 B
?)
솔루션 : 템플릿 마법을 사용하십시오! 좋아, 진지하게 당신은 전설적인 C ++ 저자 인 Andrei Alexandrescu가 제작 한 훌륭한 템플릿 메타 프로그래밍 라이브러리 인 LOKI를보고보고합니다.
보다 구체적으로 로키를 다운로드 하고 TypeManip.h
소스 코드에 헤더 를 포함 시킨 후 SuperSubclass
다음과 같이 클래스 템플릿을 사용합니다.
if(SuperSubClass<B,D>::value)
{
...
}
에 문서 SuperSubClass<B,D>::value
따르면가 B
의 공용-based 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를 사용하지 않는 한 템플릿을 사용하여 타임에만 수행 할 수 있습니다.
유형에 대한 정보를 포함하는 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
'ProgramingTip' 카테고리의 다른 글
AngularJs : 모델에 따라 체크 된 라디오 버튼을 설정하는 방법 (0) | 2020.12.06 |
---|---|
webstorm에 console.log 또는 console.info에 대한 바로 가기가 있습니까? (0) | 2020.12.06 |
클래스에 특정 멤버 변수가 있는지 여부를 감지하는 방법은 무엇입니까? (0) | 2020.12.06 |
메모장 ++를 사용하여 원격 컴퓨터에서 파일을 편집하고 수 없습니다. (0) | 2020.12.06 |
Windows 7의 PowerShell : 일반 사용자를위한 Set-ExecutionPolicy (0) | 2020.12.06 |