2010-07-16 16 views
9

Türetilmiş bir sınıfı serileştirilmiş verilerden nasıl serileştirmiyorsunuz? Ya da belki de şunu söylemeliyim ki, verileri türetilmiş sınıflara 'serileştirme' için daha iyi bir yol var mı? Örneğin, X, Y ve Z gibi diğer üç sınıf tarafından miras alınan saf bir sanal taban sınıfına (B) sahip olduğunuzu varsayalım. Ayrıca, X: B'yi çevirecek olan serialize() yöntemine sahibiz. Y: B ve Z: B, serileştirilmiş verilere.Türetilmiş bir sınıfı serileştirilmiş verilerden nasıl serileştirmiyorsunuz?

Uzak bir süreç için soket, adlandırılmış yöneltme, vb genelinde zapped edilebilir Bu şekilde.

Sahip olduğum sorun, seri hale getirilmiş verilerden uygun bir nesneyi nasıl oluşturabiliriz?

Final türetilmiş nesne türü gösterir seri veri bir tanımlayıcıyı da dahil olmak üzere bir ile gelip tek çözüm. Alıcı, önce türetilmiş tür alanını serileştirilmiş verilerden ayrıştırır ve daha sonra uygun yapıcıyı çağırmak için bir anahtar deyimi (veya bunun gibi bir çeşit mantık) kullanır. Örneğin

:

B deserialize(serial_data) 
{ 
    parse the derived type from the serial_data 

    switch (derived type) 
     case X 
      return X(serial_data) 
     case Y 
      return Y(serial_data) 
     case Z 
      return Z(serial_data) 
} 

Yani türetilmiş nesne türünü öğrendikten sonra biz uygun türetilmiş tip yapıcısı çağırmak. Bununla birlikte, bu garip ve hantal hissettiriyor. Umarım bunu yapmanın daha elverişli bir yolu vardır. Var mı?

+5

Kompakt seri (bit temelinde) dosyaların içine şeyler kaydetmek için plan, özellikle popo sağda ısırabilir. Yıllar geçtikçe ve sınıflar değiştikçe, onları tekrar yüklemeye çalıştığınızda oldukça sıkıldınız. Bu nedenle, dosyaları kendiliğinden belgelemek ve versiyon oluşturmak iyi bir fikirdir. Sadece istemci ve sunucu her zaman kullanılan protokol üzerinde anlaşırsa, düz bayt göndermek için Tamam. Değilse, o zaman ben 'XML/JSON' için başvururdum. Bununla birlikte, bunu daha kolay hale getirebilecek, örneğin 'SOAP', vb. Gibi –

+0

@Hamish +1'e de bakabilirim. –

cevap

2

Aslında, Virtual Constructor denilen serileştirme daha genel bir sorun.

geleneksel yaklaşım bir kimlik bazlı bir Factory, doğru türetilmiş tür geri döndürür. İki çözüm vardır:

// Cloneability 
class Base 
{ 
public: 
    virtual Base* clone() const = 0; 
}; 

class Derived: public Base 
{ 
public: 
    virtual Derived* clone() const { return new Derived(*this); } 
}; 

// Factory 
class Factory 
{ 
public: 
    Base* get(std::string const& id) const; 
    void set(std::string const& id, Base* exemplar); 

private: 
    typedef std::map < std::string, Base* > exemplars_type; 
    exemplars_type mExemplars; 
}; 
:

  • Eğer yığın
  • prototype yöntem üzerinde ayırmaya gerek bile, fark olarak switch yöntem

prototip yöntemi şöyle gider

Factory'u tekil yapmak gelenekseldir, ancak tamamen başka bir konu. Eğer nesne üzerinde çağırmak için sanal bir yöntem deserialize varsa

doğru serisini kaldırma için daha kolay olur.

DÜZENLEME: Fabrika nasıl çalışır?

C++ 'da, bilmediğiniz bir tür oluşturamazsınız.Yukarıdaki fikir, Derived nesnesini oluşturma görevinin clone yöntemiyle Derived sınıfına verildiği şeklindedir.

Sonraki Factory gelir. Bir "etiket" i (örneğin "Derived") bir nesnenin örneğine ilişkilendiren bir map kullanacağız (burada Derived burada). Biz (tip anında karar verilir çünkü) derleme sırasında bilmiyorum tip bir nesne oluşturmak istediğinizde Şimdi

Factory factory; 
Derived derived; 
factory.set("Derived", &derived); 

, biz fabrikaya bir etiket geçmek ve bir nesnede isteyecek dönüş.

kapağın altında
std::unique_ptr<Base> base = factory.get("Derived"); 

, Factory"Derived" etiketine bağlı Base* bulmak ve nesnenin clone yöntemi açılmasına neden olur. Bu aslında (burada) çalışma zamanı türü Derived bir nesne oluşturur.

Biz typeid operatörü kullanarak doğrulayabilirsiniz:

assert(typeid(base) == typeid(Derived)); 
+0

Cehaletimi affet. Ama bir fabrikanın problemi nasıl çözdüğünü anlamıyorum. Aslında, yukarıdaki fabrika sınıfında kamyondan düştüm. –

+0

Sorun değil, hepimiz öğrenmek için buradayız, fabrikanın sanal yapı sorununu nasıl çözdüğüne dair bir açıklama ekledim. 'Harita' yapısı ile kafanız karışmaz, sadece çalışma zamanında doldurulan süslü bir anahtardır. –

+0

Ek bilgi için teşekkür ederiz. Yani bunu doğru anlarsam. Bize ne tür bir nesne olduğunu söylemek için hala bir çeşit etikete ihtiyacımız var. Fabrika, yeni bir klon döndüren "kayıtlı" işlevi bulmak için bu etiketi kullanır. Yanılıyorsam düzeltin, ancak bu bir "dinamik" anahtar deyimine benziyor. Yukarıda gördüğüm gibi sabit kodlu bir anahtar yerine, fabrika size aynı işlevselliği sağlamak için "esnek" bir yol sunuyor? Yoksa bir şey özlüyorum. BTW, THANKS! Bu çözümü zaten yaşadığım başka bir problem için uyarladım! –

0
 
inmemory: 
-------- 
type1 { 
    chartype a; 
    inttype b; 
}; 
serialize(new type1()); 

serialized(ignore { and ,): 
--------------------------- 
type1id,len{chartypeid,adata,inttypeid,bdata} 

sanırım, ideal serileştirme protokolünde, her primitif olmayan tip, TypeId öneki len gerekmektedir. Herhangi bir şeyden türetilmeyen tek bir tür serileştirseniz bile, bir tür id eklersiniz, çünkü diğer ucun ne tür bir tür olduğunu (miras yapısından bağımsız olarak) bilmesi gerekir. Dolayısıyla, serileştirme işleminde türetilmiş sınıf kimliklerini belirtmeniz gerekir, çünkü mantıksal olarak farklı türlerdir. Eğer Yanlışsam beni düzelt.

+0

Bu, yönettiğim yönün bir türüdür, ancak uzunluğa ihtiyaç olduğunu düşünmüyorum. Tabii ki, tipidin nasıl tanımlandığına bağlı olacaktır. Bunu, sınıfın türünü tanımlamak olarak tasavvur ettim, bu da uzunluğunu da çıkaracaktır. Ancak, düşüncemin de aktarım katmanının uzunluğu bilmesi için POSIX Message Queues iletimini kullandığım gerçeğine dayandığından şüpheliyim. –

İlgili konular