2012-11-03 3 views
8

Uczę się odniesienia do C++, a teraz jestem dość zdezorientowany różnicą między nazwą zmiennej a referencją. Kod testowy znajduje się poniżej:Różnica między referencją zmiennych i nazwą

class TestClass{ 
private: 
    int num; 
public: 
    TestClass(int n):num(n){ 
     cout<<this<<" : init of : " <<this->num<<endl; 
    } 

    TestClass(const TestClass& t):num(t.num){ 
     cout<<this<<" : copyInit of : " <<this->num<<endl; 
    } 

}; 

int main(int argc, const char * argv[]){ 

    TestClass t = *(new TestClass(55)); //just to test copy initialization 

    const TestClass t2 = TestClass(100); //option1 
    const TestClass &t2 = TestClass(100); //option2 


} 

Tak więc mam dwie opcje tworzenia obiektu, które są ze sobą wyłączne.

W moim rozumieniu, jeśli użyję options2, kompilator utworzy tymczasowy obiekt w pamięci stosu i zwróci wartość odniesienia do t2.

Jeśli to prawda, w jaki sposób mogę zwerbalizować lub wyjaśnić opcję option1? Wygląda na to, że ten sam obiekt jest tworzony w pamięci stosów, a komputer nadaje mu nazwę "t2", ale nie rozumiem w jasny sposób, w jaki sposób ta opcja jest inna niż 2. nieco mylące.

Ponadto, alternatywnie przełączając opcje, mogłem zobaczyć, że obiekty są tworzone w różnych lokalizacjach pamięci w każdym przypadku. (Np przedmiotem opcja1 powstał w 0x7fff5fbff828, i że albo opcja2 był w 0x7fff5fbff820)

mógłbyś wyjaśnić

1. jaka jest różnica między nazwą zmiennej (Opcja 1) oraz odniesienia (Opcja 2) .

2. jak rzeczy działają w różny sposób w opcji 1 i 2.

3. dlaczego obiekty są tworzone w innym miejscu pamięci, zarówno w przypadkach.

Z góry dziękuję za pomoc!

+0

chciałbym podjąć próbę odpowiedzi na to pytanie, ale 3rd pytanie mnie niepokoi ... Czy kod skompilować? –

+0

@ LewsTherin Jeśli zmienisz nazwę pierwszej opcji, kompiluje. –

+0

Należy zauważyć, że w 'TestClass t = * (new TestClass (55))' nie można już "usuwać" przydzielonej pamięci. –

Odpowiedz

1

1) jaka jest różnica między nazwą zmiennej (opcja 1) a numerem referencyjnym (opcja2).

Nazwa ma typ statyczny. Odwołanie można powiązać z klasami pochodnymi - nie znamy dokładnego typu obiektów odesłanych.

W swojej samym przykładzie - dla opcji 2 - ty wydłużył żywotność tymczasowego obiektu tworząc const odniesienia do niej - patrz http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/

Normalnie, tymczasowy obiekt trwa tylko do końca pełnej wypowiedzi w którym się pojawia. Jednak C++ celowo określa, że ​​powiązanie obiektu tymczasowego z odwołaniem do stałej na stosie przedłuża czas życia tymczasowego do okresu istnienia samego odwołania, a tym samym unika tego, co w przeciwnym razie byłby wspólnym błędem odniesienia.


2) jak to wszystko działa różnie w opcji 1 i 2.

Jeśli wywołasz funkcję wirtualną - wtedy dla nazwy zmiennej wiesz, która funkcja zostanie wywołana, dla referencji - nie możesz dowiedzieć się w bardziej skomplikowanym przykładzie niż twój.


3) dlaczego obiekty są tworzone w innym miejscu pamięci w obu przypadkach.

Są różne obiekty, ich życie w tym samym czasie - więc dlaczego ich położenie pamięci powinny być identyczne?

Inne różnicą jest to, że dla opcji 1 został utworzony automatycznie zmienną, dla opcji 2 Jest to zmienna tymczasowa - obie mogą używać innej pamięci (w porównaniu stosu rejestrów lub jakąś pamięć zarezerwowaną tylko dla tymczasowych)


rozważenia bardziej skomplikowany przykład:

class TestClass{ 
protected: 
    int num; 
public: 
    TestClass(int n):num(n){ 
     cout<<this<<" : init of : " <<this->num<<endl; 
    } 
    TestClass(const TestClass& t):num(t.num){ 
     cout<<this<<" : copyInit of : " <<this->num<<endl; 
    } 
    virtual void printNum() const { cout << "NUM: " << num << endl; } 
}; 

class TestClassDerived : public TestClass { 
public: 
    TestClassDerived(int n):TestClass(n){} 
    virtual void printNum() const { cout << "DERIVED NUM: " << num << endl; } 
}; 


int main(int argc, const char * argv[]){ 
    const TestClass t1 = TestClass(100); //option1 
    const TestClass &t2 = TestClassDerived(100); //option2 
    t1.printNum(); 
    t2.printNum(); 
} 
+0

+1 za ellison :) – Caribou

+0

Co masz na myśli mówiąc "nie możesz wiedzieć"? Wygląda na to, która funkcja zostanie wywołana. – Beta

+1

Dzięki za wyjaśnienie. Czy mogę prosić o trochę więcej szczegółów? a1) W odpowiedzi 1, czy mógłbyś wyjaśnić więcej na temat typu statycznego? Kiedy zmieniłem twój przykładowy kod, tak jak to "const TestClass t2 = TestClassDerived (100);", mogłem zobaczyć, że inicjalizacja kopii miała miejsce i nowy obiekt typu superklasy jest przypisany do t2. Czy "nazwa zmiennej jako typ statyczny" oznacza, że ​​zawsze będzie reprezentować obiekt z własnym typem, poprzez utworzenie kopii przypisanego obiektu pochodnego jako zadeklarowanego typu? ** - kontynuacja ** – noclew

3
const TestClass t2 = TestClass(100); //option1 
const TestClass &t2 = TestClass(100); //option2 

Opcja 1:

wywołuje konstruktor kopiowania TestClass i przekazuje tymczasowo utworzony po prawej stronie "=". Skopiuj elizację eliminuje niepotrzebne kopiowanie obiektów (patrz: komenda Piotr poniżej).

Opcja 2:

utworzyć 1 obiekt, tymczasowy, który zostaje związany z odniesieniem.

  1. jaka jest różnica między nazwą zmiennej (Opcja 1) oraz odniesienia (Opcja 2).

edit: ja nie wiem tego wcześniej, ale w rzeczywistości nie jest to drugi przydział w opcji 1 (Dzięki Piotr) jest to spowodowane skopiować elizja który odnosi się do techniki optymalizacji kompilatora eliminuje niepotrzebne kopiowanie obiektów.

Aby użyć słowa, „nazwa zmiennej” jest blok pamięci, która zawiera dane. Odniesienie jest jak wskaźnik w tym sensie, że wskazuje na inną "nazwę zmiennej", ale musi zostać zainicjowane i nigdy nie jest puste.

  1. jak rzeczy działają w różny sposób w opcji 1 i 2.

jak mówili inni opcja 1 jest statyczny typ, gdzie w opcji 2 mogą wskazywać na wystąpienie pochodnym (z obiektu TestClass).

  1. dlaczego obiekty są tworzone w innym miejscu pamięci, zarówno w przypadkach.

mimo że „identyczne” TestObjects (100) są indywidualne przypadki, a zatem w innej pamięci (adresy)

+0

Czy możesz pokazać, jak można zmienić obiekt w opcji 1? Dla mnie wygląda na "const". – Beta

+0

@ Beta ahemm ...: | będę edytować – Caribou

+0

Jakieś dowody, że dodatkowa alokacja wystąpiła w opcji 1? Zobacz mój przykład w idee: http://ideone.com/VJiVLf. Bez dodatkowej alokacji ... – PiotrNycz