Tasarım açısından bakıldığında, neden C ++ 'da hiç temel sınıf yok, genellikle object
diğer dillerde ne var ?
typedef
s kullanmak zorundaydınız . Daha genel bir sınıf hiyerarşisiyle, sadece object
veya kullanabilirsiniz iterator
.
Tasarım açısından bakıldığında, neden C ++ 'da hiç temel sınıf yok, genellikle object
diğer dillerde ne var ?
typedef
s kullanmak zorundaydınız . Daha genel bir sınıf hiyerarşisiyle, sadece object
veya kullanabilirsiniz iterator
.
Yanıtlar:
Kesin karar Stroustrup'un SSS'lerinde bulunur . Kısacası, herhangi bir anlamsal anlam taşımaz. Bir maliyeti olacak. Şablonlar, kapsayıcılar için daha kullanışlıdır.
C ++ neden evrensel bir Object sınıfına sahip değil?
Birine ihtiyacımız yok: genel programlama, çoğu durumda statik olarak güvenli alternatifler sağlar. Diğer durumlar, çoklu miras kullanılarak ele alınır.
Yararlı bir evrensel sınıf yoktur: gerçek bir evrensel kendi başına anlambilim taşımaz.
"Evrensel" bir sınıf, türler ve arayüzler hakkında özensiz düşünmeyi teşvik eder ve aşırı çalışma süresi kontrolüne yol açar.
Evrensel bir temel sınıf kullanmak maliyet anlamına gelir: Nesnelerin polimorfik olması için yığın olarak tahsis edilmesi gerekir; bu bellek ve erişim maliyetini ifade eder. Yığın nesneleri doğal olarak kopyalama anlamını desteklemez. Öbek nesneleri, basit kapsamlı davranışı desteklemez (bu, kaynak yönetimini karmaşıklaştırır). Evrensel bir temel sınıf, dynamic_cast'in ve diğer çalışma zamanı denetimlerinin kullanılmasını teşvik eder.
Objects must be heap-allocated to be polymorphic
- Bu ifadenin genellikle doğru olduğunu düşünmüyorum. Yığın üzerinde kesinlikle bir polimorfik sınıf örneği oluşturabilir ve onu temel sınıflarından birine bir işaretçi olarak geçirerek polimorfik davranış elde edebilirsiniz.
Foo
bir referansa referans atmaya çalışmak , deterministik olarak bir istisna atar. C ++ 'da, bir işaretçiyi Foo'ya bir işaretçi çubuğuna atmaya çalışmak, Sarah Connor'ı öldürmek için zamanında bir robot gönderebilir. Bar
Bar
Foo
İlk önce neden bir temel sınıfa sahip olmak isteyeceğinizi düşünelim. Birkaç farklı neden düşünebilirim:
Smalltalk, Ruby ve Objective-C markasının dillerinin temel sınıflara sahip olmasının iki iyi nedeni bunlardır (teknik olarak Objective-C gerçekten bir temel sınıfa sahip değildir, ancak tüm niyet ve amaçlar için vardır).
# 1 için, tüm nesneleri tek bir arabirim altında birleştiren bir temel sınıfa duyulan ihtiyaç, şablonların C ++ 'ya dahil edilmesiyle ortadan kaldırılır. Örneğin:
void somethingGeneric(Base);
Derived object;
somethingGeneric(object);
parametrik polimorfizm aracılığıyla yazım bütünlüğünü baştan sona koruyabildiğiniz zaman gereksizdir!
template <class T>
void somethingGeneric(T);
Derived object;
somethingGeneric(object);
# 2 için, Objective-C'de bellek yönetimi prosedürleri bir sınıfın uygulamasının bir parçasıdır ve temel sınıftan miras alınır, C ++ 'da bellek yönetimi, miras yerine kompozisyon kullanılarak gerçekleştirilir. Örneğin, herhangi bir türdeki nesneler üzerinde referans sayımı gerçekleştirecek bir akıllı işaretçi sarıcı tanımlayabilirsiniz:
template <class T>
struct refcounted
{
refcounted(T* object) : _object(object), _count(0) {}
T* operator->() { return _object; }
operator T*() { return _object; }
void retain() { ++_count; }
void release()
{
if (--_count == 0) { delete _object; }
}
private:
T* _object;
int _count;
};
Ardından, nesnenin kendisinde yöntemler çağırmak yerine, sarmalayıcısında yöntemleri çağırırsınız. Bu sadece daha genel programlamaya izin vermekle kalmaz, aynı zamanda endişeleri ayırmanıza da olanak tanır (çünkü ideal olarak, nesneniz farklı durumlarda belleğinin nasıl yönetilmesi gerektiğinden daha çok ne yapması gerektiği ile ilgilenmelidir).
Son olarak, hem ilkellere hem de C ++ gibi gerçek nesnelere sahip bir dilde, bir temel sınıfa ( her değer için tutarlı bir arabirim ) sahip olmanın faydaları kaybolur, çünkü o zaman bu arabirime uymayan belirli değerlere sahip olursunuz. İlkelleri bu tür bir durumda kullanmak için, onları nesnelere kaldırmanız gerekir (eğer derleyiciniz bunu otomatik olarak yapmazsa). Bu çok fazla karmaşıklık yaratır.
Öyleyse, sorunuzun kısa cevabı: C ++ 'nın bir temel sınıfı yoktur çünkü şablonlar aracılığıyla parametrik polimorfizm olması gerekmez.
object
( System.Object
), ancak böyle bir şey gerekmez. Derleyiciye int
ve System.Int32
takma adlardır ve birbirlerinin yerine kullanılabilir; çalışma zamanı gerektiğinde boksla ilgilenir.
std::shared_ptr
bunun yerine C ++ 11'in artık kullanılması gerektiğini unutmayın.
C ++ değişkenleri için baskın paradigma değere göre geçirmedir, ref-by-ref değil. Her şeyi bir kökten türetilmeye zorlamak, Object
onları değere göre geçirmeyi bir hata haline getirir.
(Çünkü bir Nesneyi değere göre parametre olarak kabul etmek, tanımı gereği onu dilimlere ve ruhunu kaldırır).
Bu hoş değil. C ++, size bir seçenek sunarak, değer mi yoksa referans anlambilim mi istediğinizi düşünmenizi sağlar. Bu, performans hesaplamasında önemli bir şeydir.
Object
nispeten düşük olacaktır.
Sorun şu ki, C ++ 'da böyle bir tip var! Öyle void
. :-) Herhangi bir işaretçi, void *
temel türlere işaretçiler, sanal tablo içermeyen sınıflar ve sanal tablo içeren sınıflar da dahil olmak üzere güvenli bir şekilde dolaylı olarak kullanılabilir .
Tüm bu nesne kategorileriyle uyumlu olması gerektiğinden, void
kendisi sanal yöntemler içeremez. Sanal işlevler ve RTTI olmadan, tür hakkında hiçbir yararlı bilgi elde edilemez void
(HER türle eşleşir, bu nedenle yalnızca HER tür için doğru olan şeyleri söyleyebilir), ancak sanal işlevler ve RTTI, basit türleri çok etkisiz hale getirir ve C ++ 'nın var olmasını engeller. doğrudan bellek erişimi vb. ile düşük seviyeli programlama için uygun bir dil
Yani böyle bir tip var. Dilin düşük seviyeli doğası nedeniyle çok minimalist (aslında boş) bir arayüz sağlar. :-)
void
.
void
bildirirseniz, derlenmez ve bu hatayı alırsınız . Java'da bir tür değişkeniniz olabilir Object
ve bu işe yarar. Bu void
ve "gerçek" tip arasındaki fark budur . Belki de void
her şey için temel tür olduğu doğrudur , ancak herhangi bir kurucu, yöntem veya alan sağlamadığı için, orada olup olmadığını söylemenin bir yolu yoktur. Bu iddia kanıtlanamaz veya reddedilemez.
void
bunun bir tür olduğunu kabul ediyorum (ve biraz akıllıca bir kullanım? :
keşfettim ), ancak yine de evrensel bir temel sınıf olmaktan çok uzak. Birincisi, "tamamlanamayan tamamlanmamış bir tür" ve diğeri için void&
tür yok .
C ++ güçlü bir şekilde yazılmış bir dildir. Yine de şablon uzmanlaşması bağlamında evrensel bir nesne türüne sahip olmaması şaşırtıcı.
Örneğin, kalıbı ele alalım
template <class T> class Hook;
template <class ReturnType, class ... ArgTypes>
class Hook<ReturnType (ArgTypes...)>
{
...
ReturnType operator () (ArgTypes... args) { ... }
};
hangi şekilde örneklenebilir
Hook<decltype(some_function)> ...;
Şimdi, belirli bir fonksiyon için aynısını istediğimizi varsayalım. Sevmek
template <auto fallback> class Hook;
template <auto fallback, class ReturnType, class ... ArgTypes>
class Hook<ReturnType fallback(ArgTypes...)>
{
...
ReturnType operator () (ArgTypes... args) { ... }
};
özel örnekleme ile
Hook<some_function> ...
Ancak ne yazık ki, T sınıfı uzmanlaşmadan önce herhangi bir tür için (sınıf olsun ya da olmasın) auto fallback
ayakta durabilse de, herhangi bir tür uzmanlaşmadan önce tür olmayan şablon argümanı.
Bu nedenle, genel olarak bu kalıp, tür şablonu bağımsız değişkenlerinden tür olmayan şablon bağımsız değişkenlerine aktarılmaz.
C ++ dilindeki birçok köşede olduğu gibi, cevap muhtemelen "hiçbir komite üyesi bunu düşünmedi".
ReturnType fallback(ArgTypes...)
işe yarasa bile , kötü bir tasarım olur. template <class T, auto fallback> class Hook; template <class ReturnType, class ... ArgTypes> class Hook<ReturnType (ArgTypes...), ReturnType(*fallback)(ArgTypes...)> ...
istediğinizi yapar ve şablon parametrelerinin Hook
tutarlı türde
C ++ başlangıçta "sınıflarla C" olarak adlandırıldı. C # gibi daha modern bazı şeylerin aksine, C dilinin bir ilerlemesidir. Ve C ++ 'yı bir dil olarak değil, dillerin temeli olarak göremezsiniz (Evet, Scott Meyers'ın Etkili C ++ kitabını hatırlıyorum).
C'nin kendisi, dillerin, C programlama dilinin ve ön işlemcisinin bir karışımıdır.
C ++ başka bir karışım ekler:
sınıf / nesneler yaklaşımı
şablonlar
STL
Ben şahsen doğrudan C'den C ++ 'ya gelen bazı şeyleri sevmiyorum. Bir örnek, enum özelliğidir. C # 'nin geliştiricinin kullanmasına izin verme şekli çok daha iyidir: numaralandırmayı kendi kapsamında sınırlar, bir Count özelliğine sahiptir ve kolayca yinelenebilir.
C ++, C ile geriye dönük uyumlu olmak istediğinden, tasarımcı C dilinin bütünüyle C ++ 'ya girmesine izin verdi (bazı ince farklılıklar var, ancak bir C derleyicisini kullanarak yapabileceğiniz hiçbir şeyi hatırlamıyorum. bir C ++ derleyicisi kullanamadı).