I have a class called Child that holds a name and a list of string items. Different child objects are stored in a separate list, sort of as a nested list. The representation is:
List<"Child"> [Child1(name, List<"string">), Child2(name, List<"string">), etc.]
My objective is to create two functions: insertChild()
and insertPresent()
. The first one works, where the idea is to insert a child object into List(Child) with a specified name and List<"string">. Where I'm having trouble is with insertPresent()
, where it is supposed to search List<"Child"> given a name and, once there's a match, add a present (string) to that Child object's List<"string">.
The problem appears to be I'm accessing a local copy of the List<"string"> when calling getList()
, which explains why there appears to be no errors and the original list remains untouched after calling insertPresent()
. How do I implement the changes to access the original list and not the copy? Here's the code:
ArrayList.h:
template<class ItemType>
class ArrayList
{
private:
static const int DEFAULT_CAPACITY = 5; // Small capacity to test for a full list
ItemType items[DEFAULT_CAPACITY]; // Array of list items
protected:
int itemCount; // Current count of list items
int maxItems; // Maximum capacity of the list
public:
ArrayList();
// Copy constructor and destructor are supplied by compiler
bool isEmpty() const;
int getLength() const;
bool insert(int newPosition, const ItemType& newEntry);
bool remove(int position);
void clear();
/** @throw PrecondViolatedExcep if position < 1 or
position > getLength(). */
ItemType getEntry(int position) const throw(PrecondViolatedExcep);
/** @throw PrecondViolatedExcep if position < 1 or
position > getLength(). */
void setEntry(int position, const ItemType& newEntry) throw(PrecondViolatedExcep);
}; // end ArrayList
template<class ItemType>
ArrayList<ItemType>::ArrayList() : itemCount(0), maxItems(DEFAULT_CAPACITY)
{
} // end default constructor
template<class ItemType>
bool ArrayList<ItemType>::isEmpty() const
{
return itemCount == 0;
} // end isEmpty
template<class ItemType>
int ArrayList<ItemType>::getLength() const
{
return itemCount;
} // end getLength
template<class ItemType>
bool ArrayList<ItemType>::insert(int newPosition, const ItemType& newEntry)
{
bool ableToInsert = (newPosition >= 1) && (newPosition <= itemCount 1) &&
(itemCount < maxItems);
if (ableToInsert)
{
// Make room for new entry by shifting all entries at
// positions >= newPosition toward the end of the array
// (no shift if newPosition == itemCount 1)
for (int pos = itemCount; pos >= newPosition; pos--)
items[pos] = items[pos - 1];
// Insert new entry
items[newPosition - 1] = newEntry;
itemCount ; // Increase count of entries
} // end if
return ableToInsert;
} // end insert
template<class ItemType>
bool ArrayList<ItemType>::remove(int position)
{
bool ableToRemove = (position >= 1) && (position <= itemCount);
if (ableToRemove)
{
// Remove entry by shifting all entries after the one at
// position toward the beginning of the array
// (no shift if position == itemCount)
for (int fromIndex = position, toIndex = fromIndex - 1; fromIndex < itemCount;
fromIndex , toIndex )
items[toIndex] = items[fromIndex];
itemCount--; // Decrease count of entries
} // end if
return ableToRemove;
} // end remove
template<class ItemType>
void ArrayList<ItemType>::clear()
{
itemCount = 0;
} // end clear
template<class ItemType>
ItemType ArrayList<ItemType>::getEntry(int position) const throw(PrecondViolatedExcep)
{
// Enforce precondition
bool ableToGet = (position >= 1) && (position <= itemCount);
if (ableToGet)
return items[position - 1];
else
{
string message = "getEntry() called with an empty list or ";
message = message "invalid position.";
throw(PrecondViolatedExcep(message));
} // end if
} // end getEntry
template<class ItemType>
void ArrayList<ItemType>::setEntry(int position, const ItemType& newEntry) throw(PrecondViolatedExcep)
{
// Enforce precondition
bool ableToSet = (position >= 1) && (position <= itemCount);
if (ableToSet)
items[position - 1] = newEntry;
else
{
string message = "setEntry() called with an empty list or ";
message = message "invalid position.";
throw(PrecondViolatedExcep(message));
} // end if
} // end setEntry
Child.h:
#include "ArrayList.h"
class Child
{
private:
string name;
ArrayList<string> presents;
public:
string getName() const;
ArrayList<string> getList() const;
void setName(string name);
void setList(ArrayList<string> aList);
};
string Child::getName() const {
return name;
}
ArrayList<string> Child::getList() const {
return presents;
}
void Child::setName(string name) {
this->name = name;
}
void Child::setList(ArrayList<string> aList) {
this->presents = aList;
}
NiceArrayList.h: List<"Child">
#include <string>
#include "Child.h"
using namespace std;
template<class ItemType>
class NiceArrayList : public ArrayList<ItemType>
{
public:
/** Inserts an object containing name and aList into this list at a given position.
@pre None.
@post If 1 <= position <= getLength() 1 and the insertion is
successful, name and aList is at the given position in the nice list,
other entries are renumbered accordingly, and the returned
value is true.
@param position The list position at which to insert the object.
@param name The string assigned to the object inserted into this list.
@param aList The list assigned to the object inserted into this list.
@return True if insertion is successful, or false if not. */
bool insertChild(int position, string name, const ArrayList<string>& aList);
/** Inserts a new entry to the gift list inside an object from this
list given a name.
@pre The parameter name must be in an object in this list.
@post If 1 <= position <= getLength() 1 and the insertion is
successful, newEntry is at the given position in the gift list,
other entries are renumbered accordingly, and the returned
value is true.
@param position Theobject list position at which to insert the new entry.
@param name The string used to identify the object in this list.
@param newEntry The entry to insert into the object's list.
@return True if removal is successful, or false if not. */
bool insertPresent(string name, string newEntry);
};
template<class ItemType>
bool NiceArrayList<ItemType>::insertChild(int position, string name, const ArrayList<string>& aList) {
bool ableToInsert = false;
Child aChild;
aChild.setName(name);
aChild.setList(aList);
ableToInsert = this->insert(position, aChild);
return ableToInsert;
}
template<class ItemType>
bool NiceArrayList<ItemType>::insertPresent(string name, string newEntry) {
bool ableToInsert = false;
int length = this->getLength();
int position = 0;
for (int i = 1; i <= length; i ) {
position ;
if (this->getEntry(i).getName() == name) {
break;
}
}
//THE PROBLEM APPEARS TO BE HERE! THE INSERT DOES NOT UPDATE THE LIST!
ableToInsert = this->getEntry(position).getList().insert(1, newEntry);
return ableToInsert;
}
Sample main to test:
#include <iostream>
#include "NiceArrayList.h"
int main() {
ArrayList<string> aList1;
aList1.insert(1, "PS4");
aList1.insert(2, "PS5");
aList1.insert(3, "Toy Car");
NiceArrayList<Child> nice;
nice.insertChild(1, "John", aList1);
nice.insertPresent("John", "Phone");
return 0;
}
CodePudding user response:
Your problem is here
ArrayList<string> Child::getList() const {
return presents;
}
This is returning a copy of presents, So thios line only updates the copy
ableToInsert = this->getEntry(position).getList().insert(1, newEntry);
You need
ArrayList<string> & Child::getList() {
return presents;
}
Note the removal of the const too
and here
ArrayList<string> &getList() ;
same for getEntry on ArrayList, same fix
CodePudding user response:
getList()
was returning a copy of the sublist, so I turned the presents
attribute into a pointer of the list array and made getList()
return a reference to the array. Updated Child class:
Child.h:
#include "ArrayList.h"
class Child
{
private:
string name;
ArrayList<string>* presents;
public:
string getName() const;
ArrayList<string>& getList() const;
void setName(string name);
void setList(ArrayList<string>& aList);
};
string Child::getName() const {
return name;
}
ArrayList<string>& Child::getList() const{
return *presents;
}
void Child::setName(string name) {
this->name = name;
}
void Child::setList(ArrayList<string>& aList) {
this->presents = &aList;
}