2014-10-12 17 views
7

Java'nın instanceof'inin modern C++ 11 eşdeğerini bilmek istiyorum. Bu SO post'u görmüştüm ama çok eski ve C++ 11'de daha modern, daha iyi bir çözüm olup olmadığını merak ediyordum?C++ 11'in Java's instanceof'i nedir?

Bir manuel enum sınıfına başvurmak zorunda kalmadan bir anahtar yapısı kullanma olasılığını umuyordum.

class A { 

}; 

class B : public A { 

} 

class C : public A { 

} 

on_event(A& obj) 
{ 
    switch (obj) { 
     case A: 
     case B: 
     case C: 
    } 
} 

Benim temel sınıfımın herhangi bir sanal yöntemi veya işlevi yoktur. Bir ayrıştırıcı için bir ifade ağacı temsil ediyorum ve taban sınıfı sadece bir polimorfik tutucu - Haskell/OCaml'de bir ADT gibi.

+3

"dynamic_cast <>" soruyor musunuz? Bu, C++ 11'e özgü değil. –

+0

Hiçbir şey değişmedi: standart C++'da yansıma yoktur. Çalışma zamanı türü bilgilerini açmak istiyorsanız, 'dynamic_cast' – quantdev

+0

İlginizi çekebilir: http://stackoverflow.com/q/25495733/596781 –

cevap

12

aynı cevabı hala geçerlidir ve her zaman C++ böyle olmuştur:

if (C * p = dynamic_cast<C *>(&obj)) 
{ 
    // The type of obj is or is derived from C 
} 
else 
{ 
    // obj is not a C 
} 

Bu yapı sanal üye işlevleri olması, polimorfik olduğu yani A gerektirir.

Ayrıca, bu davranış Java'nın instanceof yanı sıra dinamik döküm oysa tam tip kimlik için ikinci testler beri typeid(obj) == typeid(C) karşılaştırarak farklı olduğuna dikkat, hedef türü için sadece bir test türü bir temel sınıf olmak en türetilmiş nesne.

+1

da, bazı C++ kullanıcıları için bir tür acı olan 'RTTI' gerektirir. – user2485710

+1

@ user2485710: Bu ifadenin * dil * C++ bağlamında anlamlı olduğunu düşünmüyorum. Kod, yeterlilik olmadan geçerli C++. –

+1

Eğer "RTTI" 'ye sahip değilseniz, o şey işe yaramazsa, ne düşündüğünüzün önemi yoktur, sadece bu kod parçasının düzgün çalışması için gereklidir. – user2485710

-1

Kendinizi derleme zamanında bilinen türlerle sınırlamak istiyorsanız (vtables ile sınıfların örneklerinde işaretçiler aracılığıyla çalışmak yerine) - sonra C++ 11 ve üstü instanceof eşdeğerine sahiptir: std::is_base_of.

Ayrıca std::is_convertible ve std::is_same adreslerini de incelemek isteyebilirsiniz.

+3

Bir işlev şablonu yapmadıkça ve derleme zamanında türleri bilmedikçe bunun nasıl yardımcı olabileceğinden emin değilim. Çalışma zamanı polimorfizmi hakkında konuştuğu oldukça açık olduğunu düşünüyorum. – PeterT

+0

@PeterT: Tamamen katılmıyorum. Yani, C++ 'da, özellikle Modern C++' da, derleme zamanı bilinen türlerle bir çok şey yaparız, bu yüzden bu tam olarak geçerli bir cevaptır (düzenlense bile). – einpoklum

0

C++ düz eski verilerinde (POD) çalışma zamanı türü bilgisi yoktur. Tanımlanan sınıflar, tam olarak 1 bayt alır ve boş bir temel sınıf optimizasyonu olan herhangi bir derleyicide aynı çalışma zamanı temsilcilerine sahiptir.

İstediğiniz gibi yapılamaz.

Temel sınıfına sanal bir yıkıcı eklemek, RTTI'ye eklenir ve dynamic_cast desteği. Her türetilmiş sınıf için farklı bir şekilde başlatılan tabana enum veya int alan ekleme .

Yine bir başka seçenek şöyle bir şablon işlevi oluşturmak ve bir işaretçi saklamaktır:

using my_type_id=void(*)(); 
template<class>void get_my_type_id_helper(){}; 
template<class T> my_type_id get_my_type_id(){return get_my_type_id_helper<T>;} 

ve daha sonra bir my_type_id uygun başlatıldı A depolamak. Bu RTTI'yi yeniden icat ediyor ve daha fazla özellik istedikçe C++ RTTI ek yüküne yaklaşacaksınız.

C++ 'da sadece sizin için ne istediğini ödersiniz: RTTI olmadan sınıflar isteyebilir, bunu yaptırabilir ve alabilirsiniz.

RTTI Çalıştırma Zamanı Türü Bilgileri'dir. POD düz eski veriler, bir C++ 03 terimidir. Birçok sınıf POD değildir: kolay yol virtual destructor eklemektir. C++ 11, daha ince taneli standart düzen ve toplu şartlara sahiptir. Teknik olarak RTTI ve POD, birbirinin karşıtları değildir: PTI olmayan RTTI'si olmayan sınıflar vardır.

MSVC'nin RTTI üretmeme seçeneklerine ve saldırgan Comdat katlanmasının, her iki durumda da standardın ihlaline yol açtığı manuel RTTI'yi bozabileceğini unutmayın.

-1

Bunu yapma. Çoğu durumda, instanceof veya dynamic_cast için sorduğunuzda tasarımınızı gözden geçirmelisiniz.

Neden? Büyük olasılıkla Liskov's substitiontin principle ihlal ediyor.

nasıl bu yaklaşım hakkında: @Yakk belirttiği gibi en az bir virtual yöntem zaten dinamik polimorfizm almak gerektiğini

class A { 
    public: 
    virtual void action(); 
    virtual ~A(); 
}; 

class B : public A { 
    public: void action() override; 
}; 

class C : public A { 
    public: void action() override; 
}; 

void on_event(A& obj) 
{ 
    obj.action(); 
} 

Not. Ve şöyle bir kural var: En az bir sanal yönteme sahip olduğunuzda, daima temel sınıfta bir sanal yıkıcı yazınız.

Tüm bunları şablonlar ve uzmanlıkla yapabilir veya etiketleme yazabilirsiniz, ancak sorunuzu - Java'dan geliyor - oraya gitmek istemiyorsunuz. Gerçekten gibi sanal yöntemler gibi, değil mi? Üzgünüz, bunları C++ olarak işaretlemeniz gerekiyor.

+0

3 sınıftan (A, B, C) oluşan bir programın LSP'yi ihlal ettiğini ve iyi bir tasarım olarak değerlendirilebileceğini düşünmüyorum. LSP bölümünün yanıltıcı olmasından dolayı aşağı çekmek istemiştim (soru C++ 11 için instanceof'e doğrudan alternatifle ilgili ve uyarılarınızda bağlantıda daha önce de belirtilmişti), ancak birisi bunu yararlı bulabilir. – m039