3

I'm teaching myself C++ hence the awful naming and super simple question. I'm trying to concatenate two arrays in C++. The array are of type string. Their constructor allows for them to have a default capacity of 12. So basically I'm trying to combine the arrays so that I have an array capable of holding 24 elements. I don't want to use vectors and I don't wanna use STL. The arrays have some items but they don't completely fill up their capacity. Below you'll find the code.

Here's my ArrayBag.h class def:

#ifndef _ARRAY_BAG
#define _ARRAY_BAG
#include "BagInterface.h"
#include <vector>


template<class ItemType>
class ArrayBag : public BagInterface<ItemType>
{
private:
    static const int DEFAULT_CAPACITY = 24; // the bag size a bit bigger to allow
                                            // adding bags.
    ItemType items[DEFAULT_CAPACITY];      // Array of bag items
    int itemCount;                         // Current count of bag items
    int maxItems;                          // Max capacity of the bag

    // Returns either the index of the element in the array items that
    // contains the given target or -1, if the array does not contain
    // the target.
    int getIndexOf(const ItemType& target) const;

public:
    ArrayBag();
    int getCurrentSize() const;
    bool isEmpty() const;
    bool add(const ItemType& newEntry);
    void clear();
    bool remove(const ItemType& anEntry);
    bool contains(const ItemType& target) const;
    int getFrequencyOf(const ItemType& anEntry) const;
    std::vector<ItemType> toVector() const;
}; // end ArrayBag

#endif

And here's my actual class implementation.

#include "ArrayBag.h"
#include <cstddef>

template<class ItemType>
ArrayBag<ItemType>::ArrayBag(): itemCount(0), maxItems(DEFAULT_CAPACITY)
{
}  // end default constructor

template<class ItemType>
int ArrayBag<ItemType>::getCurrentSize() const
{
    return itemCount;
}  // end getCurrentSize

template<class ItemType>
bool ArrayBag<ItemType>::isEmpty() const
{
    return itemCount == 0;
}  // end isEmpty

template<class ItemType>
bool ArrayBag<ItemType>::add(const ItemType& newEntry)
{
    bool hasRoomToAdd = (itemCount < maxItems);
    if (hasRoomToAdd)
    {
        items[itemCount] = newEntry;
        itemCount++;
    }  // end if

    return hasRoomToAdd;
}  // end add

template<class ItemType>
void ArrayBag<ItemType>::clear()
{
    itemCount = 0;
}  // end clear

template<class ItemType>
bool ArrayBag<ItemType>::remove(const ItemType& anEntry)
{
    int locatedIndex = getIndexOf(anEntry);
    bool canRemoveItem = !isEmpty() && (locatedIndex > -1);
    if (canRemoveItem)
    {
        itemCount--;
        items[locatedIndex]=items[itemCount];
    }//end if
    return canRemoveItem;
} //end remove

template<class ItemType>
bool ArrayBag<ItemType>::contains(const ItemType& anEntry) const
{
    bool found = false;
    int curIndex = 0; //current array index
    while(!found && (curIndex < itemCount))
    {
        if(anEntry == items[curIndex])
        {
            found = true;
        } //end if

        curIndex++; //increment to the next entry
    } //end while
    return found;
}

template<class ItemType>
int ArrayBag<ItemType>::getFrequencyOf(const ItemType& anEntry) const
{
    int frequency = 0;
    int curIndex = 0; //current index array
    while(curIndex < itemCount)
    {
        if (items[curIndex] == anEntry)
        {
            frequency++;
        } //end if

        curIndex++; //incremenet to next entry
    } //end while
    return frequency;
} //end getFrequencyOf


template<class ItemType>
vector<ItemType> ArrayBag<ItemType>::toVector() const
{
    vector<ItemType> bagContents;
    for (int i = 0; i < itemCount; i++)
        bagContents.push_back(items[i]);

    return bagContents;
}  // end toVector

ArrayBag<string> merge(const ArrayBag<string>& oneBag,
                       const ArrayBag<string>& anotherBag)
{
    int sizeOnebag, sizeAnotherbag, newBagsize;
         sizeOnebag = oneBag.getCurrentSize();
         sizeAnotherbag = anotherBag.getCurrentSize();
         newBagsize = sizeAnotherbag + sizeOnebag;

In the above, I've taken the size of the two bags and created a new int that holds the size of the two original arrays. But from there I'm not sure what to do. I've tried the below. But get a compiler warning each time.

 ArrayBag<string> finalBag;

     int itemCount = finalBag.getCurrentSize();

     if (itemCount > newBagsize){
         newBagsize++;
         itemCount = finalBag.getCurrentSize();
         finalBag[itemCount];
     }

Below is BagInterface.h

#ifndef _BAG_INTERFACE
#define _BAG_INTERFACE

#include <vector>
using namespace std;

template<class ItemType>
class BagInterface
{
public:
    /** Gets the current number of entries in this bag.
     @return The integer number of entries currently in the bag. */
    virtual int getCurrentSize() const = 0;

    /** Sees whether this bag is empty.
     @return True if the bag is empty, or false if not. */
    virtual bool isEmpty() const = 0;

    /** Adds a new entry to this bag.
     @post  If successful, newEntry is stored in the bag and
     the count of items in the bag has increased by 1.
     @param newEntry  The object to be added as a new entry.
     @return  True if addition was successful, or false if not. */
    virtual bool add(const ItemType& newEntry) = 0;

    /** Removes one occurrence of a given entry from this bag,
     if possible.
     @post  If successful, anEntry has been removed from the bag
     and the count of items in the bag has decreased by 1.
     @param anEntry  The entry to be removed.
     @return  True if removal was successful, or false if not. */
    // virtual bool remove(const ItemType& anEntry) = 0;

    /** Removes all entries from this bag.
     @post  Bag contains no items, and the count of items is 0. */
    virtual void clear() = 0;

    // I commented this out because I did not implement it.
    /** Counts the number of times a given entry appears in bag.
     @param anEntry  The entry to be counted.
     @return  The number of times anEntry appears in the bag. */

    virtual int getFrequencyOf(const ItemType& anEntry) const = 0;

     // I commented this out because I did not implement it.

    /** Tests whether this bag contains a given entry.
     @param anEntry  The entry to locate.
     @return  True if bag contains anEntry, or false otherwise. */


    virtual bool contains(const ItemType& anEntry) const = 0;

    /** Empties and then fills a given vector with all entries that
     are in this bag.
     @return  A vector containing all the entries in the bag. */
    virtual vector<ItemType> toVector() const = 0;

    virtual bool remove(const ItemType& anEntry) = 0;
}; // end BagInterface
#endif

And here is my main file.

    #include <iostream>
#include <string>
#include "ArrayBag.h"

using namespace std;

void displayBag(ArrayBag<string>& bag)
{
    cout << "The bag contains " << bag.getCurrentSize()
    << " items:" << endl;
    vector<string> bagItems = bag.toVector();
    int numberOfEntries = (int)bagItems.size();
    for (int i = 0; i < numberOfEntries; i++)
    {
        cout << bagItems[i] << " ";
    }  // end for
    cout << endl << endl;
}  // end displayBag

void displayBag(ArrayBag<int>& bag)
{
    cout << "The bag contains " << bag.getCurrentSize()
    << " items:" << endl;
    vector<int> bagItems = bag.toVector();
    int numberOfEntries = (int)bagItems.size();
    for (int i = 0; i < numberOfEntries; i++)
    {
        cout << bagItems[i] << " ";
    }  // end for
    cout << endl << endl;
}  // end displayBag

int sumOfBag(ArrayBag<int>& aBag)
{
    int sum=0;
    vector<int> aBagvector = aBag.toVector();
    int numberOfEntries = (int) aBagvector.size();
    for (int i = 0; i < numberOfEntries; i++)
    {
        sum += aBagvector[i];
    }
    //cout << "The sum of the bag is " << sum << endl;
    return sum;
}

void bagTester(ArrayBag<string>& bag)
{
    cout << "isEmpty: returns " << bag.isEmpty()
    << "; should be 1 (true)" << endl;
    displayBag(bag);

    string items[] = {"one", "two", "three", "four", "five", "one"};
    cout << "Add 6 items to the bag: " << endl;
    for (int i = 0; i < 6; i++)
    {
        bag.add(items[i]);
    }  // end for

    displayBag(bag);

    cout << "isEmpty: returns " << bag.isEmpty()
    << "; should be 0 (false)" << endl;

    cout << "getCurrentSize: returns " << bag.getCurrentSize()
    << "; should be 6" << endl;

    cout << "Try to add another entry: add(\"extra\") returns "
    << bag.add("extra") << endl;
    displayBag(bag);
} // end bagTester


int main()
{
    ArrayBag<string> bag;
    cout << "Testing the Array-Based Bag:" << endl;
    cout << "The initial bag is empty." << endl;
    bagTester(bag);
    ArrayBag<string> bag_of_strings1;
    string items[] = {"tom","dick","harry"};
    for (int i=0; i<3; i++) {bag_of_strings1.add(items[i]);}
    displayBag(bag_of_strings1);
    ArrayBag<string> bag_of_strings2;
    string new_items[] = {"now","is","the","time","for","all"};
    for(int i=0; i<6; i++){
        bag_of_strings2.add(new_items[i]);
    }
    displayBag(bag_of_strings2);
    //ArrayBag<string> newbag=merge(bag_of_strings1,bag_of_strings2);

    //displayBag(newbag);

    ArrayBag<int> bag_of_ints;
    int array_of_ints[]={6,7,85,9,12,15};
    for (int i=0;i<6;i++){
        bag_of_ints.add(array_of_ints[i]);
    }
    displayBag(bag_of_ints);
    cout<<sumOfBag(bag_of_ints)<<endl;

    return 0;
} // end main
KFDoom
  • 772
  • 1
  • 6
  • 19
  • Alright you got me there. – KFDoom Jul 21 '15 at 00:44
  • What warning do you get and why is that a problem? – twsaef Jul 21 '15 at 00:51
  • The warning I get is that I do not provide a subscript operation for ArrayBag however I don't think overloading my operators is the solution here. I'm certain there's a much simpler solution. – KFDoom Jul 21 '15 at 00:54
  • I think you want help with the implementation of your ArrayBag::merge method. Is that correct? – twsaef Jul 21 '15 at 01:03
  • @KacheFlowe `ItemType items[DEFAULT_CAPACITY]; ` Arrays are fixed in size. You cannot resize them. – PaulMcKenzie Jul 21 '15 at 01:12
  • Right. Yet when I tried to change the constructor capacity I still kept getting the same error. – KFDoom Jul 21 '15 at 01:13
  • @KacheFlowe What do you mean by "change the constructor capacity"? You cannot change the size of an array at runtime. It is that simply put. Your class requires a dynamically allocated buffer, not a fixed size array. – PaulMcKenzie Jul 21 '15 at 01:15
  • I see. I realize that the solution would be much simpler if I used something like a vector (I don't know what a dynamically allocated buffer is but I'll google it soon) but the point of me trying this exercise is to solve it without having to use Dynamic data types or easy solutions. – KFDoom Jul 21 '15 at 01:17
  • 3
    @KacheFlowe In all seriousness, writing code to do these types of things, unless you are experienced in C++, is not as trivial as you may seem to believe. It is just not made for beginners. Arrays cannot be resized at runtime. You need to create your own vector class that declares a pointer, allocates memory, manages the memory correctly, deallocates the memory without issues, make sure the class is exception safe, etc. etc. That is a lot of work to cover and know about before even attempting something like this. – PaulMcKenzie Jul 21 '15 at 01:20
  • Ah ha! I see. Then I will most likely implement the simpler solution (and try the subscript operator solution provided by @kirbyfan64sos below). Thank you. – KFDoom Jul 21 '15 at 01:22

2 Answers2

2

You can declare merge as a friend:

public:
friend ArrayBag<string> merge(ArrayBag<string> a, ArrayBag<string> b);
ArrayBag();
int getCurrentSize() const;
bool isEmpty() const;
...

Then define merge like:

ArrayBag<string> merge(ArrayList<string> a, ArrayList<string> b) {
    int newsz = a.getCurrentSize() + b.getCurrentSize();
    if (newsz > a.DEFAULT_CAPACITY)
        // do something here
        abort();
    ArrayBag<string> result;
    for (int c=0; c<a.getCurrentSize(); ++c)
        result.add(a.items[c]);
    for (int c=0; c<b.getCurrentSize(); ++c)
        result.add(b.items[c]);
    return result;
}

Of course, the cleaner way is to add a subscript operator:

T operator[](size_t x) const { return items[x]; }

Then you don't need merge to be a friend and can replace a.items[c] and b.items[c] with just a[c] and b[c].

kirbyfan64sos
  • 10,377
  • 6
  • 54
  • 75
  • I'm sorry since I'm essentially asking you to spoon feed this to me but how do I actually implement the subscript operator? This is what I have now: ArrayBag merge(ArrayBag a, ArrayBag b) { T operator[](size_t x) const { return items[x]; } – KFDoom Jul 23 '15 at 23:44
  • 1
    @KacheFlowe You need to put the declaration in your class, not in the `merge` function. – kirbyfan64sos Jul 23 '15 at 23:59
  • I'm assuming the declaration would be a public function in the .h file then? – KFDoom Jul 24 '15 at 00:01
  • Yes. I will post my BagInterface.h and main file. – KFDoom Jul 24 '15 at 01:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/84130/discussion-between-kacheflowe-and-kirbyfan64sos). – KFDoom Jul 24 '15 at 02:30
  • This did not end up answering my question. – KFDoom Jul 24 '15 at 03:32
0

You haven't shown your code for ArrayBag, but if you want to merge two C-style arrays, you will have to make a new array with 24 elements and manually copy (or move if using C++11 or C++14) the elements over, then delete the old arrays.

By the way, assuming you are using std::string, you are already using the STL.

rlbond
  • 65,341
  • 56
  • 178
  • 228