2012-06-20 17 views
5

Bir nesnenin en türetilmiş sınıfını, miras ağacındaki sınıflardan birinin yapıcısı içinde keşfetmeye çalışıyorum. Bu konuda birkaç saat harcadım ve başka nasıl yapabileceğimi ya da neden mantıklı gelmediğini kaybettim. Mükemmel bir his gibi görünüyor, ama işe yaramaz. RTTI hakkında çok sayıda sayfa buldum ve temelde hiçbir yerde onlarla birlikte olmadım. Test durumumdan ve çıktısından sonra açıklamaya devam edeceğim."Bu" işaretçisi RTTI etkin mi?

kaynak: (++ g üzerinde)

#include <iostream> 
#include <typeinfo> 
#include <string> 

class A 
{ 
public: 
    A(std::string foo); 

    virtual void bar(A* a) = 0; 
}; 

class B : public A 
{ 
public: 
    B(); 

    virtual void bar(A* a); 
}; 

A::A(std::string foo) 
{ 
    std::cout << "type as passed to A constructor: " << foo << " (" << this << ")" << std::endl; 
    std::cout << "type as determined in A constructor: " << typeid(*this).name() << " (" << this << ")" << std::endl; 
} 

B::B() : A(typeid(*this).name()) 
{ 
    A* a = (A*)this; 
    std::cout << "type as determined in B constructor: " << typeid(*a).name() << " (" << this << ")" << std::endl; 
    this->bar(this); 
} 

void B::bar(A* a) 
{ 
    std::cout << "type as determined in bar: " << typeid(*a).name() << " (" << a << ")" << std::endl; 
} 

int main() 
{ 
    B b; 
    b.bar(&b); 

    return 0; 
} 

çıkışı:

type as passed to A constructor: 1B (0x7fff5fbff910) 
type as determined in A constructor: 1A (0x7fff5fbff910) 
type as determined in B constructor: 1B (0x7fff5fbff910) 
type as determined in bar: 1B (0x7fff5fbff910) 
type as determined in bar: 1B (0x7fff5fbff910) 

yerine "1A" nın "1B" demek için çıktı ikinci satırını almaya çalışıyorum . RTTI, henüz hayal edemediğim bir nedenden dolayı "bu" dan ayrıldı mı? Bu sanal fonksiyonlar fikrini nasıl kırmaz? (Daha önce tanımadığım RTTI'nin bir kısmını yeniden keşfettiğimi keşfedene kadar bunu sanal işlevlerle uygulamıştım.) Çıktının gösterdiği gibi, “bunu” kullanmaktan kaçınırsam bu işi yapabilirim. Bunu yapmak tasarımla kırılmaya benziyor.

+2

Neden bu türü algılamaya çalışıyorsunuz? Bu ungood. Bu başka bir şeye teşebbüs (kusurlu) bir çözüm gibi geliyor, başka bir şey nedir? –

+0

Alf, std :: map türünde (std :: string, bu durumda) nesnelerin her bir türü harita içinde benzersiz bir nesneye sahip. Belirli bir sınıfın her bir örneğinin, yeni nesnelerin bu temel nesnelere kolayca eklenmesini ve daha sonra türüne göre alınmasını sağlamak için kendi haritası vardır. (Bunu, aynı nedenden ötürü eşdeğer bir başarısızlıkla, RTTI'yı bilmeden önce, const ints ve sanal yöntemlerle yapıyordum.) – Grault

cevap

4

Bunu yapamazsınız çünkü ilgili dinamikleri yanlış anlayabilirsiniz.

kural: yapıcı/yıkıcı o sınıfa herhangi bir sınıf noktalarının

yapıcısında this/yıkıcı.

Ayrıca, bu normalde dinamik sevk kullanırken çalışmak için bir virtual fonksiyonu beklediğiniz gibi yapıcı olarak adlandırılan virtual fonksiyonları davranmazlar nedenidir.

Sen yapıcı called.You yapıcı ve yoketme hariç üye fonksiyonunda herhangi yapabilirsiniz olmuştur sonra tip, algılamalıdır.

+0

Peki, neden bu daha iyi olarak değerlendiriliyor? Bana göre, en iyi görünmez gibi görünüyor. Başka bir OO özelliğini kırmak mı? – Grault

0

Kalıtım ilişkinizi dikkate alın, önce A yapıcısının ilk önce çalıştırılacağını ve B öğesinin ne olacağını bilmeniz gerekir. A yapıcı içinde, henüz oluşturulmadığı için nesne B değildir. Bu nedenle, bir kurucudaki bir nesnenin dinamik türü, her zaman sınıfın kendisinin türü ve asla türetilmiş bir sınıfın türü değildir. Aynı yıkıcılar içinde olur.

Kısacası, ne yapmak istediğiniz yapım aşamasında yapılamaz.

+0

"A’nın kurucusu ilk önce ve sonra B’den biri olacaktır." Ben “bu” kelimesini bir kurucuya (test vakasında dolaylı olarak kanıtlanmış olan) bir kurucuya geçirebildiğim kadar düşünmüştüm. Şimdi akışı ilk önce yürüten en türetilmiş kurucu olarak anlıyorum ve her kurucu başka bir şey yapmadan önce üst öğeyi çağırıyor. Böylece bedenler söylediğin gibi kökten aşağı doğru koşarlar. – Grault

3

Beklenen davranışları görüyorsunuz. Bir yapıcının gövdesinde, yapım aşamasında olan nesnenin türü, inşa edilen en türetilmiş sınıfın sınıfı değil, kurucusunun yürütüldüğü sınıfın tipi ile aynıdır. Üye başlatıcısı ifadesi kullanıldığında

anomali ifadesi typeid(*this) içinde gerçekten. Bu, C++ 03'te tanımsız davranışı olarak kullanılır, ancak bu, C++ 11'de değiştirilmiştir, böylece oluşturulacak gerçek nesnenin türü yerine, yapıcının sınıfının türünü elde edersiniz.