Czy wewnątrz i na temat wygenerowanego kodu istnieje różnica między:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
i
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
dzięki...
Odpowiedzi:
Zakładając, że te wartości są typami pierwotnymi, to nie, nie ma różnicy. Listy inicjalizacyjne mają znaczenie tylko wtedy, gdy masz obiekty jako elementy członkowskie, ponieważ zamiast używać domyślnej inicjalizacji, po której następuje przypisanie, lista inicjalizacyjna umożliwia zainicjowanie obiektu do jego ostatecznej wartości. W rzeczywistości może to być zauważalnie szybsze.
Musisz użyć listy inicjalizacyjnej, aby zainicjować stałe składowe, odwołania i klasę bazową
Kiedy musisz zainicjować stały element członkowski, odwołania i przekazać parametry do konstruktorów klasy bazowej, jak wspomniano w komentarzach, musisz użyć listy inicjalizacyjnej.
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
};
Przykładowa (niewyczerpująca) klasa / struktura zawiera odniesienie:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
I przykład inicjalizacji klasy bazowej, która wymaga parametru (np. Brak domyślnego konstruktora):
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
i _len
mają typy klas bez dostępnych domyślnych konstruktorów?
const
elementu członkowskiego w treści konstruktora, musisz użyć listy inicjalizacyjnej - osoby niebędące const
składnikami mogą zostać zainicjowane w liście inicjalizacyjnej lub w treści konstruktora.
Tak. W pierwszym przypadku można zadeklarować _capacity
, _data
a _len
jako stałe:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
Byłoby to ważne, jeśli chcesz zapewnić const
-ness tych zmiennych instancji podczas obliczania ich wartości w czasie wykonywania, na przykład:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const
wystąpienia muszą być zainicjowane na liście inicjatorów lub typy bazowe muszą zapewniać publiczne konstruktory bez parametrów (które robią typy pierwotne).
Myślę, że ten link http://www.cplusplus.com/forum/articles/17820/ daje doskonałe wyjaśnienie - szczególnie dla tych, którzy są nowicjuszami w C ++.
Powodem, dla którego listy inicjalizujące są bardziej wydajne, jest to, że w treści konstruktora odbywają się tylko przypisania, a nie inicjalizacja. Więc jeśli masz do czynienia z typem niewbudowanym, domyślny konstruktor dla tego obiektu został już wywołany przed wprowadzeniem treści konstruktora. W treści konstruktora przypisujesz wartość do tego obiektu.
W efekcie jest to wywołanie domyślnego konstruktora, po którym następuje wywołanie operatora przypisania kopiowania. Lista inicjalizatorów umożliwia bezpośrednie wywołanie konstruktora kopiującego, co czasami może być znacznie szybsze (pamiętaj, że lista inicjalizacyjna znajduje się przed ciałem konstruktora)
Dodam, że jeśli masz elementy typu klasy bez domyślnego konstruktora, inicjalizacja jest jedynym sposobem na zbudowanie Twojej klasy.
Prawdziwa różnica sprowadza się do tego, jak kompilator gcc generuje kod maszynowy i rozkłada pamięć. Wyjaśnić:
Z pewnością istnieją inne sposoby obsługi składowych typu const. Aby jednak ułatwić sobie życie, twórcy kompilatorów gcc decydują się na ustanowienie pewnych reguł
Istnieje tylko jeden sposób inicjowania wystąpień klas bazowych i niestatycznych zmiennych składowych, a jest to użycie listy inicjalizatora.
Jeśli nie określisz podstawowej lub niestatycznej zmiennej składowej na liście inicjalizatora twojego konstruktora, to ten element członkowski lub baza zostanie zainicjowana domyślnie (jeśli element członkowski / baza jest typem klasy innym niż POD lub tablicą klasy innej niż POD typy) lub pozostawione niezainicjowane w inny sposób.
Po wprowadzeniu treści konstruktora wszystkie bazy lub składowe zostaną zainicjowane lub pozostawione niezainicjowane (tj. Będą miały nieokreśloną wartość). W treści konstruktora nie ma możliwości wpływania na sposób ich inicjalizacji.
Możesz mieć możliwość przypisania nowych wartości do elementów członkowskich w treści konstruktora, ale nie jest możliwe przypisanie do const
elementów członkowskich lub elementów członkowskich typu klasy, których nie można przypisać, i nie jest możliwe ponowne powiązanie odwołań.
W przypadku typów wbudowanych i niektórych typów zdefiniowanych przez użytkownika przypisanie w treści konstruktora może mieć dokładnie taki sam efekt, jak inicjowanie z tą samą wartością na liście inicjatorów.
Jeśli nie możesz nazwać członka lub bazy na liście inicjalizatorów, a ta jednostka jest referencją, ma typ klasy bez dostępnego konstruktora domyślnego zadeklarowanego przez użytkownika, jest const
kwalifikowana i ma typ POD lub jest typem klasy POD lub tablicą typu klasy POD zawierającego const
kwalifikowanego członka (bezpośrednio lub pośrednio), program jest źle sformułowany.
Jeśli napiszesz listę inicjalizującą, zrobisz wszystko w jednym kroku; jeśli nie napiszesz listy inicjalizatora, wykonasz 2 kroki: jeden do deklaracji i jeden do przypisania wartości.
Istnieje różnica między listą inicjalizacyjną a instrukcją inicjalizacyjną w konstruktorze. Rozważmy poniższy kod:
#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;
}
Gdy używana jest MyClass, wszyscy członkowie zostaną zainicjowani przed pierwszą instrukcją w wykonywanym konstruktorze.
Ale gdy jest używana MyClass2, wszyscy członkowie nie są inicjowani, gdy wykonywana jest pierwsza instrukcja w konstruktorze.
W późniejszym przypadku może wystąpić problem z regresją, gdy ktoś dodał kod w konstruktorze przed zainicjowaniem określonego elementu członkowskiego.
Oto punkt, o którym nie widziałem, aby inni się do niego odnosili:
class temp{
public:
temp(int var);
};
Klasa tymczasowa nie ma domyślnego ctora. Kiedy używamy go w innej klasie w następujący sposób:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
kod się nie skompiluje, ponieważ kompilator nie wie jak zainicjalizować obj
, ponieważ ma tylko jawny ctor, który otrzymuje wartość int, więc musimy zmienić ctor w następujący sposób:
mainClass(int sth):obj(sth){}
Więc nie chodzi tylko o const i referencje!