Hello ladies and gents,

I'm trying to include a copy constructor and an assignement operator into this code wich has two separate classes, the idea is to copy the last name that was entered. Problem is, I can't seem to grasp how to get acces to the copy constructor in main nor am I sure that the copy constructor is written correctly?

Could someone help me out with this program:

//Lobby
//Simulate a lobby where people wait

#include <iostream>
#include <string>

using namespace std;

class Person
{
public:
    Person(const string& name = ""):m_Name(name), m_pNext(NULL){}
    Person(const Person& copyName);
    string GetName() const { return m_Name;}
    Person* GetNext() const { return m_pNext;}
    void SetNext(Person* next) { m_pNext = next;}
    
private:
    string m_Name;
    Person* m_pNext;    // pointer to next name in list
};

Person::Person(const Person& copyName)
{
    cout << "Copy constructor called...\n";
    
    m_pNext = new Person;
    *m_pNext = copyName.GetName();
}

class Lobby
{
    friend ostream& operator<<(ostream& os, const Lobby& aLobby);

public:
    Lobby():m_pHead(NULL){}
    ~Lobby() { Clear();}
    
    void AddName();
    void RemoveName();
    void Clear();
    
private:
    Person* m_pHead;
};

void Lobby::AddName()
{
    //create a new name node
    cout << "Please enter the name of the new person: ";
    string name;
    cin >> name;
    Person* pNewName = new Person(name);
    
    //if list is empty, make head of list this new name
    if (m_pHead == NULL)
    {
        m_pHead = pNewName;
    }
    //otherwise find the end of the list and add the name there
    else
    {
        Person* pIter = m_pHead;
        
        while (pIter->GetNext() != NULL)
        {
                pIter = pIter->GetNext();
        }
        pIter->SetNext(pNewName);
    }
}

void Lobby::RemoveName()
{
    if (m_pHead == NULL)
    {
        cout << "The lobby is empty. No one to remove.\n";
    }
    else
    {
        Person* pTemp = m_pHead;
        m_pHead = m_pHead->GetNext();
        delete pTemp;
    }
}

void Lobby::Clear()
{
    while (m_pHead != NULL)
    {
        RemoveName();
    }
}

ostream& operator<<(ostream& os, const Lobby& aLobby)
{
    Person* pIter = aLobby.m_pHead;
    
    os << "\nHere's who's in the lobby:\n";
    
    if (pIter == NULL)
    {
        os << "The lobby is empty.\n";
    }
    else
    {
        while (pIter != NULL)
        {
                os << pIter->GetName() <<  endl;
                pIter = pIter->GetNext();
        }
    }
    return os;
}

int main()
{
    Lobby myLobby;
    int choice;
    
    do
    {
        cout << myLobby;
        cout << "\nLOBBY\n";
        cout << "0 - Exit the program.\n";
        cout << "1 - Add a person to the lobby.\n";
        cout << "2 - Remove a person from the lobby.\n";
        cout << "3 - Clear the lobby.\n";
        cout << "4 - Copy the last name.\n";
        cout << endl << "Enter choice: ";
                
        cin >> choice;
        
        switch(choice)
        {
                case 0:
                cout << "Good-bye.\n";
                break;
                case 1:
                myLobby.AddName();
                break;
                case 2:
                myLobby.RemoveName();
                break;
                case 3:
                myLobby.Clear();
                break;
                //case 4:
                //Person.             //<-- how to write the link to getting
                //break;              //the copy???
                default:
                cout << "That was not a valid choice.\n";
        
        }
    } while (choice != 0);
    
    cout << "Press enter to exit!\n";
    
    cin.ignore(1, '\0');
    
    return 0;
}

Thank you.

Recommended Answers

All 7 Replies

Person::Person(const Person& copyName) :
{
    cout << "Copy constructor called...\n";
    
      m_name= copyName.GetName();
      m_pNext = 0;  //or m_pNext = copyName.m_pNext; if you want both copies to have the same address in their pointers.  
}

Thanks for the help Lerner, but how do I call the copy constructor in main when I want to copy the last name that was entered then?

And also, could the copy constructor be written for the Lobby class aswell?

Thanks.

if you had a Person, p, in main() and wanted to copy p into Person p1 using a copy constructor then you could do this:

Person p1(p);

If p1 already exists in main() and you want to copy something else into p1 after it's already been constructed, then you could write a copy method in addition to a copy constructor. Say you are given a Person in the form of Person pointer, *pPerson, and you wanted to copy it into an existing Person, p1, rather than having p1 be a copy of p. Then it would be:

p1.copyPerson(*pPerson);

where copyPerson() was a method of the Person class taking a Person parameter and copying the data into another Person.

Yes, you can/should implement a copy constructor for the Lobby class. In fact, the compiler will do it for you if you don't do it. To my knowledge, all classes need at least a non-copy constructor, a copy contstructor, a destructor, and an assignment operator. If you don't write one of each for your class/struct, the compiler will do it for you, and you may not like the results, or you may say thank you very much and leave it go at that, depending on the situation.

Why not use the assignment operator rather than the CopyPerson() method?

Actually most classes will work perfectly will with the compiler generated copy constructor, destructor & assignment operator.
Only classes which do their own resource mgmt need them.

In the case of People & Lobby classes, the design is overly complicated by incorporating the 'list' into both classes.
eg what should happen when a People object is destroyed?
should it be removed from the linked chain?
What if the obj is a copy of an obj which is in the list?
etc...

Why not use a list<People> or vector<People> in the Lobby class & remove this complication from the People class?

Thanks for the additional help guys, but, I seem not to be able to grasp how to write this copy constructor or assignement operator for the program. No worries though, it was just an exercise I was trying to make from a book.

Why I wanted to do it the way I described is because it was written that way in that book and with that code, I had to write them. Suppose like you've said, there are better ways to solve this, though, would have like to be able to solve it the way it was asked in that book.

Darn, so frustrating from time to time when you can't seem to grasp how the hell that piece of code is supposed to fit into that program :rolleyes: :D

I'll put it aside and return to it again when I understand the meaning of it all abit better because for instance, to me, it seems a copy constructor and an assignement operator are the same thing. Difference I seem to see is that a copy constructor make a deep copy in wich it gives the object it's own adress and an assignement operator gives one object the value of another object, wich is the same as copying right :?:

Pfff, so confusing from time to time :o

Copy constructors and assignment operators frequently look and act a lot alike. The difference is that copy constructors create a new object given the data in an already existing object whereas the assignment operator assigns the data in one existing object into another existing object, meaning no new object is created in the process. Since it makes no sense to copy/assign the data of an object into itself, assignment operator code frequently checks for identity of rhs and lhs objects before proceeding, whereas with the copy constructor there is no existing object to use as an lhs object so there can't be identity. Otherwise, you can (frequently) copy the code of the copy constructor into assignment operator code.

The biggest problem in your code that I can see is the following line:

*m_pNext = copyName.GetName();

copyName.GetName() returns a string, whereas *m_pNext is a Person, not a string, so it's hard assigning a string to a Person. Change *m_pNext to m_name and the code looks pretty good to me (haven't compiled it though). Also, why use the new operator when implementing the Copy constructor. Copy constructors make new objects using static memory. If you want to use dynamic memory to create a new object, then use the new operator, as you do in the addName() method.

To answer my own question, you would use the new operator in the copy constructor if you wanted to create a deep copy instead of a shallow copy. A shallow copy is when the information is copied directly from the object to be copied into the new copy of the object. This means that if the object contains a pointer, that the new copy will contain the same address in the pointer that the old copy had. Thus you could change the information at the address in the pointer in the old copy by changing the information in the new copy. Sometimes this is what you want, and sometimes it isn't. You might want the data at the address of the pointer in the old copy to be copied into the new object so you can change it without changing the information in the old object. To do this you would populate the pointer in the new copy of the object with a new memory address using the new operator, and then copy the data from the old copy pointers address into the new copy's pointer address. This can create a problem in that you now have to release the memory that you allocated in the new copy of the object. That is usually done in the destructor. But if you call delete on a pointer whose memory wasn't allocated with the new operator and that isn't null you will have a problem. This c/would happen if an object created with the default constructor, or non-copy constructor doesn't allocate memory to the pointer contained therein with the new operator. So, often if you want to allocate memory in the copy constructor using the new operator so you can do a deep copy, then all constructors will use the new operator to allocate memory for the same pointer for their objects so the destructor can delete the dynamic memory from all objects created of that class, rather than trying to keep track of which objects are created by the copy constructor and contain dynamic memory that should be deleted manually and which objects are created by non-copy constructor(s) and therefore don't contain dynamic memory and shouldn't have memory deleted manually. Are there other ways to deal with this dilema besides having all constructors use dynamic memory if want to do deep copy with copy constructors; probably, but they are probably even more complicated.

How do you know what to do when, where? In my opinion, it's only through practice, but then maybe that's my rationalization for the incomplete/misleading information I had provided in my previous post (and this one too?).

Good luck. Keep reading. Keep coding.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.