Dahili olarak ve üretilen kod hakkında, aşağıdakiler arasında gerçekten bir fark var mı:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
ve
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
Teşekkürler...
Yanıtlar:
Bu değerlerin ilkel türler olduğunu varsayarsak, hayır, hiçbir fark yoktur. Başlatma listeleri, yalnızca üye olarak nesneleriniz olduğunda bir fark yaratır, çünkü varsayılan başlatma ve ardından atama kullanmak yerine, başlatma listesi nesneyi nihai değerine başlatmanıza izin verir. Bu aslında fark edilir derecede daha hızlı olabilir.
Sabit üyeleri, referansları ve temel sınıfı başlatmak için başlatma listesini kullanmanız gerekir
Sabit üyeyi, referansları başlatmanız ve parametreleri temel sınıf yapıcılarına iletmeniz gerektiğinde, yorumlarda belirtildiği gibi, başlatma listesini kullanmanız gerekir.
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
Örnek (kapsamlı olmayan) sınıf / yapı başvuru içerir:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
Ve bir parametre gerektiren temel sınıfı başlatma örneği (ör. Varsayılan kurucu yok):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
_capacity
, _data
ve _len
erişilebilir bir varsayılan kurucular olmadan sınıf türleri var mı?
const
yapıcı gövdesinde başlatamazsınız , başlatma listesini kullanmanız gerekir - const
üye olmayanlar başlatma listesinde veya yapıcının gövdesinde başlatılabilir.
Evet. İlk durumda _capacity
, _data
ve _len
sabitler olarak beyan edebilirsiniz :
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
Çalışma const
zamanında değerlerini hesaplarken bu örnek değişkenlerinin -ness'ini sağlamak istiyorsanız bu önemli olacaktır , örneğin:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const
örnekleri gerekir başlatıcı listesinde başlatılması ya da altta yatan türleri (ilkel türleri do) Kamu parametresiz kurucular sağlamalıdır.
Sanırım bu http://www.cplusplus.com/forum/articles/17820/ bağlantısının mükemmel bir açıklama sağladığını düşünüyorum - özellikle C ++ 'da yeni olanlar için.
Başlatıcı listelerinin daha verimli olmasının nedeni, kurucu gövdesi içinde, başlatmanın değil, yalnızca atamaların yer almasıdır. Bu nedenle, yerleşik olmayan bir türle uğraşıyorsanız, o nesnenin varsayılan kurucusu, kurucunun gövdesi girilmeden önce zaten çağrılmıştır. Yapıcı gövdesinin içinde, o nesneye bir değer atarsınız.
Aslında bu, varsayılan kurucuya yapılan bir çağrı ve ardından kopyalama-atama operatörüne yapılan bir çağrıdır. Başlatıcı listesi, kopya oluşturucuyu doğrudan çağırmanıza izin verir ve bu bazen önemli ölçüde daha hızlı olabilir (başlatıcı listesinin yapıcının gövdesinden önce olduğunu hatırlayın)
Varsayılan kurucunun olmadığı sınıf türü üyeleriniz varsa, sınıfınızı oluşturmanın tek yolunun başlatma olduğunu ekleyeceğim.
Büyük bir fark, atamanın bir üst sınıfın üyelerini başlatabilmesidir; başlatıcı yalnızca geçerli sınıf kapsamında bildirilen üyeler üzerinde çalışır.
İlgili türlere bağlıdır. Aradaki fark benzer
std::string a;
a = "hai";
ve
std::string a("hai");
burada ikinci biçim başlatma listesi - yani, türün yapıcı bağımsız değişkenleri gerektirmesi veya yapıcı bağımsız değişkenleriyle daha verimli olması fark yaratır.
Gerçek fark, gcc derleyicisinin makine kodunu nasıl ürettiği ve belleği nasıl yerleştirdiğiyle ilgilidir. Açıklamak:
Const tipi üyeleri kullanmanın kesinlikle başka yolları da vardır. Ancak hayatlarını kolaylaştırmak için gcc derleyici yazarları bazı kurallar koymaya karar verir
Temel sınıf örneklerini ve statik olmayan üye değişkenleri başlatmanın tek bir yolu vardır ve bu da başlatıcı listesini kullanmaktır.
Oluşturucunuzun başlatıcı listesinde bir temel veya statik olmayan üye değişken belirtmezseniz, bu üye veya taban varsayılan olarak başlatılır (üye / taban POD olmayan bir sınıf türü veya POD dışı sınıf dizisi ise) türleri) veya aksi takdirde başlatılmamış bırakılır.
Yapıcı gövdesine girildikten sonra, tüm bazlar veya üyeler başlatılmış veya sıfırlanmamış bırakılmış olacaktır (yani, belirsiz bir değere sahip olacaklardır). Yapıcı gövdede, bunların nasıl başlatılacağını etkileme fırsatı yoktur.
Yapıcı gövdesindeki üyelere yeni değerler atayabilirsiniz, ancak const
atanamaz hale getirilmiş sınıf türündeki üyelere veya üyelere atamak ve referansları yeniden atamak mümkün değildir.
Yerleşik türler ve bazı kullanıcı tanımlı türler için, yapıcı gövdesinde atama, başlatıcı listesindeki aynı değerle başlatma ile tam olarak aynı etkiye sahip olabilir.
Bir başlatıcı listesindeki bir üyeyi veya tabanı adlandırmada başarısız olursanız ve bu varlık bir başvuru ise, kullanıcı tarafından tanımlanmış erişilebilir const
bir kurucuya sahip olmayan bir sınıf türüne sahipse, uygunsa ve POD türüne sahipse veya bir POD sınıfı türü veya POD sınıf türü dizisi ise const
kalifiye bir üye içeriyorsa (doğrudan veya dolaylı olarak) program kötü biçimlidir.
Bir başlatıcı listesi yazarsanız, hepsini tek adımda yaparsınız; Bir başlatıcı listesi yazmazsanız, 2 adım yapacaksınız: biri bildirim için, diğeri de değeri atamak için.
Bir yapıcıdaki başlatma listesi ile başlatma ifadesi arasında bir fark vardır. Aşağıdaki kodu ele alalım:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
MyClass kullanıldığında, tüm üyeler, çalıştırılan bir yapıcıdaki ilk ifadeden önce başlatılacaktır.
Ancak MyClass2 kullanıldığında, bir yapıcıdaki ilk ifade çalıştırıldığında tüm üyeler başlatılmaz.
Daha sonraki durumda, belirli bir üye başlatılmadan önce birisi kurucuya bazı kodlar eklediğinde regresyon sorunu olabilir.
İşte başkalarının buna değindiğini görmediğim bir nokta:
class temp{
public:
temp(int var);
};
Temp sınıfının varsayılan bir ctoru yoktur. Aşağıdaki gibi başka bir sınıfta kullandığımızda:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
kod derlenmez, derleyicinin nasıl başlatılacağını bilmemesine obj
neden olur, çünkü sadece bir int değeri alan açık bir ctor'a sahiptir, bu nedenle ctor'u aşağıdaki gibi değiştirmeliyiz:
mainClass(int sth):obj(sth){}
Yani, bu sadece sabit ve referanslarla ilgili değil!