Please explain this section of code for me :(

Hi everyone, so recently i just started studying some advanced OOP and there's something that i didn't quite understood. Here's the full code:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <iostream>
#include <string>

using namespace std;

class Critter
{
public: 
    Critter(const string& name = "", int age = 0);  
    ~Critter();                   //destructor prototype   
    Critter(const Critter& c);    //copy constructor prototype
    Critter& Critter::operator=(const Critter& c);  //overloaded assignment op
    void Greet() const; 

private:
    string* m_pName;
    int m_Age;
};

Critter::Critter(const string& name, int age)
{
    cout << "Constructor called\n";
    m_pName = new string(name);
    m_Age = age;  
}

Critter::~Critter()                        //destructor definition
{
    cout << "Destructor called\n";
    delete m_pName;
}

Critter::Critter(const Critter& c)        //copy constructor definition
{
    cout << "Copy Constructor called\n";
    m_pName = new string(*(c.m_pName));
    m_Age = c.m_Age;
}
//i don't understand this part:
Critter& Critter::operator=(const Critter& c)  //overloaded assignment op
{
    cout << "Overloaded Assignment Operator called\n";
    if (this != &c)
    {
        delete m_pName;
        m_pName = new string(*(c.m_pName));
        m_Age = c.m_Age;
    }
    return *this;
}

void Critter::Greet() const
{
     cout << "I'm " << *m_pName << " and I'm " << m_Age << " years old. ";
     cout << "&m_pName: " << cout << &m_pName << endl;
}

void testDestructor();
void testCopyConstructor(Critter aCopy);
void testAssignmentOp();

int main()
{
    testDestructor();
    cout << endl;
    
    Critter crit("Poochie", 5);
    crit.Greet();
    testCopyConstructor(crit);
    crit.Greet();
    cout << endl;
    
    testAssignmentOp();

    return 0;
}

void testDestructor()
{
    Critter toDestroy("Rover", 3);
    toDestroy.Greet();
}

void testCopyConstructor(Critter aCopy)  
{
    aCopy.Greet();
}

void testAssignmentOp()
{
    Critter crit1("crit1", 7);
    Critter crit2("crit2", 9);
    crit1 = crit2;
    crit1.Greet();  
    crit2.Greet();
    cout << endl;
        
    Critter crit3("crit", 11);
    crit3 = crit3;
    crit3.Greet();
}


I understood everything except the overloaded assignment section, why did we do Critter& like this as a reference? i know what the this keyword does but why did we return *this like that? to a reference (Critter&) this doesn't make any sense.
Last edited on
this is a Critter&* in that context.
Basically, doing return *this; returns a Critter& of the "current" object.

Also, (your question was a bit weird), you pass it as a reference to avoid useless copies of the objects.

This allows for: crit1 = crit2 = crit3;
Last edited on
ehh... nope didn't understand, what do you mean by this is a Critter&*
Last edited on
this is a pointer to a reference.
*this returns the reference.
ohh now that makes sense, thanks
hold on, you call an overloaded operator, and then call one that doesn't exist? How is that supposed to work??

Also, why not return void?
^ What? Quote some code, I don't get it.

EDIT: Found a mistake on line 56:
You wrote "cout" in the middle.
cout should only be at the beginning.
Last edited on
http://ideone.com/BJItho
Hehe, in the context of line 56 that will make things a little confusing.

EDIT: What the, why is m_pName a pointer to a std::string? Why is it a pointer!?
http://stackoverflow.com/questions/7945638/should-i-use-pointer-to-stdstring
You should not use a pointer to a std::string, ever. I can see no case in which it would be beneficial to do so (correct me if I'm wrong, but even if there is a case I think it would be very rare).
Last edited on
Basically lines 40 to 50 are about implementing the assignments in lines 3, 4 and 5 of:
1
2
3
4
5
Critter a;
Critter b;
b = a;
Critter c = a;
a = a;


The class Critter has two member variables:
1
2
string* m_pName;
int m_Age;

which need to be changed during the assignment process.

Effectively what needs to happen is:
1
2
b.m_pName = a.m_pName;
b.m_Age = a.m_Age;


This would be easy, apart from two problems. First there is a pointer (m_pName). Secondly what happens if we are assigning to ourselves:
a = a;

Dealing with the second problem, line 43 fixes this, ie no need to do anything! It is worth checking that this works with some test code!

Dealing with the first problem, if we simply copy the pointers:
b.m_pName = a.m_pName;
then both pointers would point to the same data, and when the destructor of one free's that data (line 30), the other will possibly get corrupted when the storage is re-used, or be invalid, or throw an exception when it tries to be free'd a second time. So line 46 allocates new storage for the string, initializes it, and sets the m_pName pointer to point to it. However, what of the original memory pointed to by b.m_pName? It is de-allocated in line 45, so no memory leaks.

This type of problem (copying classes with pointers) is covered very well in a number of places:
http://www.cplusplus.com/articles/y8hv0pDG/
http://pages.cs.wisc.edu/~hasti/cs368/CppTutorial/NOTES/CLASSES-PTRS.html
http://stackoverflow.com/questions/5033232/c-class-copy-pointer-copy

Last edited on
This is why you should avoid pointers as much as you can. Smart pointer classes will cause the default copy constructors and assignment operators to be deleted, which means you will get errors for trying to perform copies or assignments, thus eliminating the issue with regular pointers and forcing you to create a proper implementation.
I'm kind of late but, there's no such thing as a "pointer to a reference". References don't have memory locations (actually for practical reasons, implementations generally give them memory locations, but they're impossible to obtain without undefined behavior). In non-static members of T, this is a 'T *' or a 'const T *', and *this is a T or const T. A T is implicitly convertible to T & and const T &.
Well, my fault then.
Topic archived. No new replies allowed.