मैं का उपयोग करने की तर्ज पर सोच रहा था, typeid()
लेकिन मुझे नहीं पता कि कैसे पूछें कि क्या प्रकार एक अन्य वर्ग का उपवर्ग है (जो, वैसे, सार है)
मैं का उपयोग करने की तर्ज पर सोच रहा था, 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();
}
संपादित करें: चूंकि इस उत्तर के बारे में बहस इतने सालों के बाद भी जारी है, मैंने सोचा कि मुझे कुछ संदर्भों में फेंक देना चाहिए। यदि आपके पास एक बेस क्लास का पॉइंटर या संदर्भ है, और आपके कोड को ऑब्जेक्ट की व्युत्पन्न क्लास को जानना है, तो यह लिस्कोव प्रतिस्थापन सिद्धांत का उल्लंघन करता है । अंकल बॉब इसे " ऑब्जेक्ट ओरिएंटेड डिज़ाइन के लिए एक" एंथेमा कहते हैं।
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<>
यहाँ की आवश्यकता है? static_cast<>
पर्याप्त नहीं होगा ?
x
संकलन के समय का प्रकार बता सकते हैं ? अगर ऐसा है तो static_cast<>()
काम करेंगे। यदि आप x
रनटाइम तक का प्रकार नहीं बता सकते हैं तो आपको जरूरत हैdynamic_cast<>()
आप इसे कर सकते हैं dynamic_cast
(कम से कम बहुरूपी प्रकार के लिए)।
वास्तव में, दूसरे विचार पर - आप यह नहीं बता सकते हैं कि क्या यह विशिष्ट रूप से एक विशेष प्रकार है dynamic_cast
- लेकिन आप यह बता सकते हैं कि क्या यह उस प्रकार का है या उसका कोई उपवर्ग है।
template <class DstType, class SrcType>
bool IsType(const SrcType* src)
{
return dynamic_cast<const DstType*>(src) != nullptr;
}
std::is_polymorphic_v<T>
है false
।
नीचे दिया गया कोड इसे करने के 3 अलग-अलग तरीकों को प्रदर्शित करता है:
#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
यह निर्धारित कर सकता है कि क्या प्रकार में वंशानुक्रम पदानुक्रम में कहीं भी लक्ष्य प्रकार शामिल है (हाँ, यह एक अल्पज्ञात विशेषता है कि यदि B
विरासत से A
और C
, यह A*
सीधे में बदल सकता है C*
)। typeid()
वस्तु का सटीक प्रकार निर्धारित कर सकते हैं। हालांकि, इन दोनों को बेहद संयम से इस्तेमाल किया जाना चाहिए। जैसा कि पहले ही उल्लेख किया गया है, आपको हमेशा गतिशील प्रकार की पहचान से बचना चाहिए, क्योंकि यह एक डिजाइन दोष को इंगित करता है। (यह भी, यदि आप जानते हैं कि ऑब्जेक्ट लक्ष्य प्रकार के बारे में सुनिश्चित करने के लिए है, तो आप इसके साथ डाउनकास्ट कर सकते हैं static_cast
। बूस्ट ऑफर करता है polymorphic_downcast
कि डीबग मोड के साथ dynamic_cast
और assert
डीबग मोड में, और रिलीज मोड में यह सिर्फ एक का उपयोग करेगा static_cast
)।
मैं असहमत हूं कि आपको कभी भी C ++ में ऑब्जेक्ट के प्रकार की जांच नहीं करनी चाहिए। यदि आप इससे बच सकते हैं, तो मैं सहमत हूं कि आपको चाहिए। यह कहना कि आपको किसी भी परिस्थिति में ऐसा नहीं करना चाहिए, हालांकि बहुत दूर जा रहा है। आप इसे कई भाषाओं में कर सकते हैं, और यह आपके जीवन को बहुत आसान बना सकता है। उदाहरण के लिए, हावर्ड पिंसले ने हमें दिखाया कि कैसे C # पर उनकी पोस्ट में।
मैं क्यूटी फ्रेमवर्क के साथ बहुत काम करता हूं। सामान्य तौर पर, मैं मॉडल करता हूं कि वे चीजों को करने के बाद क्या करते हैं (कम से कम जब उनके ढांचे में काम करते हैं)। QObject क्लास सभी Qt ऑब्जेक्ट्स का बेस क्लास है। उस वर्ग के पास एक त्वरित उपवर्ग चेक के रूप में फ़ंक्शन WWgetgetType () और 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
(या इसके विपरीत) का उपवर्ग है ?
समाधान: कुछ टेम्पलेट जादू का उपयोग करें! ठीक है, गंभीरता से आपको LOKI पर एक नज़र डालने की ज़रूरत है, जो कि एक उत्कृष्ट टेम्पलेट मेटा-प्रोग्रामिंग लाइब्रेरी है जिसे f C C लेखक आंद्रेई अलेक्जेंड्रेस्कु द्वारा निर्मित किया गया है।
अधिक विशेष रूप से, LOKI डाउनलोड करें और 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
मैं का उपयोग करने की तर्ज पर सोच रहा था
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
}
}
जब तक आप RTTI का उपयोग नहीं करते हैं, आप इसे केवल टेम्पलेट्स का उपयोग करते हुए संकलन समय पर कर सकते हैं।
यह आपको टाइपिड फ़ंक्शन का उपयोग करने देता है जो कि एक type_info संरचना के लिए एक संकेतक प्राप्त करेगा जिसमें प्रकार के बारे में जानकारी होती है।
विकिपीडिया पर इसे पढ़ें
सी # में आप बस कह सकते हैं:
if (myObj is Car) {
}
आप इसे टेम्प्लेट्स (या SFINAE (सबस्टीट्यूशन फेल्योर इज़ नॉट ए एरर)) के साथ कर सकते हैं। उदाहरण:
#include <iostream>
class base
{
public:
virtual ~base() = default;
};
template <
class type,
class = decltype(
static_cast<base*>(static_cast<type*>(0))
)
>
bool check(type)
{
return true;
}
bool check(...)
{
return false;
}
class child : public base
{
public:
virtual ~child() = default;
};
class grandchild : public child {};
int main()
{
std::cout << std::boolalpha;
std::cout << "base: " << check(base()) << '\n';
std::cout << "child: " << check(child()) << '\n';
std::cout << "grandchild: " << check(grandchild()) << '\n';
std::cout << "int: " << check(int()) << '\n';
std::cout << std::flush;
}
आउटपुट:
base: true
child: true
grandchild: true
int: false
std::is_base_of
वांछित के रूप में काम नहीं करेगा। : 3