SORU
15 Mayıs 2011, Pazar


Neden bir c sınıfı standart bir dize sağlanmalı değil mi?

Belirli bir noktaya Etkili C yapılan soracaktım .

Diyor ki:

Bir yıkıcı bir sınıf edilmiş bir sınıf gibi hareket etmeye ihtiyacı varsa sanal yapılmalıdır. Daha fazla std::string sanal bir yıkıcı olmadığı için, bir daha asla buradan gerektiğini de sözlerine ekledi. Ayrıca std::string bile bir temel sınıf, polimorfik temel sınıf unutmak için tasarlanmamıştır.

Özellikle temel bir sınıf olduğu için hak kazanmak için bir sınıf (polimorfik) gerekli olan şey anlamıyorum?

std::string sınıf türetmek gerektiğini tek sebebi bu sanal bir yıkıcı değil mi? Yeniden kullanım amacı için bir temel sınıf tanımlanabilir ve çoklu türetilmiş sınıf devralır. std::string bile temel bir sınıf olarak uygun kılan nedir?

Ayrıca, eğer bir temel sınıf tamamen tanımlanan yeniden kullanım amacı ve pek çok türetilmiş türleri, herhangi bir şekilde önlemek için istemci yapıyor Base* p = new Derived() çünkü sınıflar yok olmak için kullanılan polymorphically?

CEVAP
15 Mayıs 2011, Pazar


Bu deyim karışıklığı burada (vurgu benim) yansıttığını düşünüyorum:

Özellikle temel clas olmak için uygun olması için bir sınıf gerekli olan şey anlamıyorum (değil, çok biçimli bir)?

Deyimsel C , bir sınıf türetmek için iki kullanımı vardır:

  • özelmiras, mixins ve boy yönelimli programlama şablonları kullanarak için kullanılır.
  • kamumiras için kullanılırpolimorfik durumlarda sadece.EDİTTamam, bu bir kaç kendisine dahil ederse, bir senaryo CRTP kullanıldığında ortaya çıkan boost::iterator_facade gibi de kullanılabilir sanırım.

Eğer polimorfik bir şeyler yapmaya çalışıyorsan halka, C sınıfı türetmek için kesinlikle bir neden yok. Dil, standart bir özellik olarak özgür fonksiyonları ile birlikte gelir ve ücretsiz işlevleri burada kullanıyor olması gerekir.

Şöyle düşünün çok basit birkaç yöntem tack istediğin için mi kod müşterilerine bazı özel string sınıfı kullanarak dönüştürmek için zorlamak istiyor musunuz? C temel sınıfın çoğu kullanıcı bir değişiklik bu tür hakkında bilmeniz gereken bir sınıf oluşturmak. çünkü farklı olarak Java veya C# (ya da en benzer nesne yönelimli dil), C# sınıfları Java/genellikle benzer olan başvurular, erişilir C 'nin işaretçiler. Bu nedenle, sınıf müşteriler diğer müşteriler bilmeden türetilmiş bir sınıf yerine izin decouples olan yönlendirme dahil olamamıştı.

Ancak, C , sınıflarıdeğer türleri-- OO diğer birçok dilde farklı olarak. Bunu görmenin en kolay yolu the slicing problem olarak bilinir. Temel olarak, göz önünde bulundurun:

int StringToNumber(std::string copyMeByValue)
{
    std::istringstream converter(copyMeByValue);
    int result;
    if (converter >> result)
    {
        return result;
    }
    throw std::logic_error("That is not a number.");
}

Eğer bu yöntemi kendi dize geçirirseniz, std::string için kopya yapıcı bir kopyasını yapmak için çağrılırdeğil kopya türetilmiş bir nesne için yapıcı-- std::string alt sınıfa geçti ne olursa olsun. Bu yöntemlerin bir şey dize bağlı arasında tutarsızlık neden olabilir. İşlevi StringToNumber sadece ne olursa olsun senin türetilmiş nesne ve anlaşıldı, çünkü sizin türetilmiş nesne muhtemelen bir farklı boyutu daha bir std::string Bu işlev, derlenmiş rezerv sadece uzay için std::string otomatik depolama. Ve Java, C# Bu otomatik depolama yapan tek şey başvuru türleri, çünkü bu bir sorun değil, kaynaklar hep aynı boyutta. C değil .

Uzun lafın kısası -- C yöntemleri üzerinde tack miras kullanmayın . Dil ile ilgili sorunları deyimsel ve sonuçları değil. Kullanımı mümkün olmayan arkadaşım, üye olmayan fonksiyonlar, kompozisyon izledi. Şablon veya polimorfik davranış istiyorum metaprogramming değilsen miras kullanmayın. Daha fazla bilgi için, Scott Meyers'in Effective C Madde 23: üye olmayan arkadaş olmayan üye işlev görür. Tercih bakın

EDİT: İşte Dilimleme sorunu gösteren. daha kapsamlı bir örnek codepad.org çıktısını görebilirsiniz

#include <ostream>
#include <iomanip>

struct Base
{
    int aMemberForASize;
    Base() { std::cout << "Constructing a base." << std::endl; }
    Base(const Base&) { std::cout << "Copying a base." << std::endl; }
    ~Base() { std::cout << "Destroying a base." << std::endl; }
};

struct Derived : public Base
{
    int aMemberThatMakesMeBiggerThanBase;
    Derived() { std::cout << "Constructing a derived." << std::endl; }
    Derived(const Derived&) : Base() { std::cout << "Copying a derived." << std::endl; }
    ~Derived() { std::cout << "Destroying a derived." << std::endl; }
};

int SomeThirdPartyMethod(Base /* SomeBase */)
{
    return 42;
}

int main()
{
    Derived derivedObject;
    {
        //Scope to show the copy behavior of copying a derived.
        Derived aCopy(derivedObject);
    }
    SomeThirdPartyMethod(derivedObject);
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Marissah Simonini

    Marissah Sim

    25 HAZİRAN 2013
  • RogerBuckChrist

    RogerBuckChr

    9 Temmuz 2011
  • Trevor Eckhart

    Trevor Eckha

    19 Aralık 2009