0

I was given 4 files, ArrayBag.cpp/.hpp and Animal.cpp/.hpp. The goal is to create a new class, ZooRecord and implement it in respective cpp and hpp files. This class inherits from ArrayBag and stores Animal objects.

// Header file for an array-based implementation of the ADT bag.


#ifndef ARRAY_BAG_
#define ARRAY_BAG_

#include <vector>
#include <string>


template<class T>
class ArrayBag
{

public:
    /** default constructor**/
    ArrayBag();
    
    /**
     @return item_count_ : the current size of the bag
    **/
    int getCurrentSize() const;
    
    /**
     @return true if item_count_ == 0, false otherwise
     **/
    bool isEmpty() const;
    
    /**
     @return true if new_etry was successfully added to items_, false otherwise
     **/
    bool add(const T& new_entry);
    
    /**
     @return true if an_etry was successfully removed from items_, false otherwise
     **/
    bool remove(const T& an_entry);
    
    /**
     @post item_count_ == 0
     **/
    void clear();
    
    /**
     @return true if an_etry is found in items_, false otherwise
     **/
    bool contains(const T& an_entry) const;
    
    /**
     @return the number of times an_entry is found in items_
     **/
    int getFrequencyOf(const T& an_entry) const;
    
    /**
     @return a vector having the same cotntents as items_
     **/
    std::vector<T> toVector() const;

    /** display the contents of the bag to standard output in the form “item1, item2, … , itemN\n” **/
    std::string display();

    void operator+=(const ArrayBag<T>& a_bag);

    void operator-=(const ArrayBag<T>& a_bag);

    void operator/=(const ArrayBag<T>& a_bag);





    
    
    
    
protected:
    static const int DEFAULT_CAPACITY = 200;  //max size of items_
    T items_[DEFAULT_CAPACITY];              // Array of bag items
    int item_count_;                         // Current count of bag items
    
   
    /**
     @param target to be found in items_
     @return either the index target in the array items_ or -1,
     if the array does not containthe target.
     **/
    int getIndexOf(const T& target) const;
    
    
}; // end ArrayBag

#endif

/** Implementation file for the class ArrayBag.
 @file ArrayBag.cpp */

#include "ArrayBag.hpp"
#include <iostream>

/** default constructor**/
template<class T>
ArrayBag<T>::ArrayBag(): item_count_(0)
{
}  // end default constructor


/**
 @return item_count_ : the current size of the bag
 **/
template<class T>
int ArrayBag<T>::getCurrentSize() const
{
    return item_count_;
}  // end getCurrentSize


/**
 @return true if item_count_ == 0, false otherwise
 **/
template<class T>
bool ArrayBag<T>::isEmpty() const
{
    return item_count_ == 0;
}  // end isEmpty


/**
 @return true if new_etry was successfully added to items_, false otherwise
 **/
template<class T>
bool ArrayBag<T>::add(const T& new_entry)
{
    bool has_room = (item_count_ < DEFAULT_CAPACITY);
    if (has_room)
    {
        for(int i = 0; i < item_count_; i++) {
            if (items_[i] == new_entry) {
                return false; // duplicate item found
            }
        }
        items_[item_count_] = new_entry;
        item_count_++;
        return true;
    }  // end if

    return false;
}  // end add


/**
 @return true if an_etry was successfully removed from items_, false otherwise
 **/
template<class T>
bool ArrayBag<T>::remove(const T& an_entry)
{
   int found_index = getIndexOf(an_entry);
    bool can_remove = !isEmpty() && (found_index > -1);
    if (can_remove)
    {
        item_count_--;
        items_[found_index] = items_[item_count_];
    }  // end if

    return can_remove;
}  // end remove


/**
 @post item_count_ == 0
 **/
template<class T>
void ArrayBag<T>::clear()
{
    item_count_ = 0;
}  // end clear


/**
 @return the number of times an_entry is found in items_
 **/
template<class T>
int ArrayBag<T>::getFrequencyOf(const T& an_entry) const
{
   int frequency = 0;
   int cun_index = 0;       // Current array index
   while (cun_index < item_count_)
   {
      if (items_[cun_index] == an_entry)
      {
         frequency++;
      }  // end if

      cun_index++;          // Increment to next entry
   }  // end while

   return frequency;
}  // end getFrequencyOf


/**
 @return true if an_etry is found in items_, false otherwise
 **/
template<class T>
bool ArrayBag<T>::contains(const T& an_entry) const
{
    return getIndexOf(an_entry) > -1;
}  // end contains


/**
 @return a vector having the same cotntents as items_
 **/
template<class T>
std::vector<T> ArrayBag<T>::toVector() const
{
   std::vector<T> bag_contents;
    for (int i = 0; i < item_count_; i++)
        bag_contents.push_back(items_[i]);

   return bag_contents;
}  // end toVector

template<class T>
std::string ArrayBag<T>::display() {
    std::string result;
    for (int i = 0; i < item_count_; i++) {
        result += std::to_string(items_[i]);
        if(i < item_count_ -1 )
            result += ", ";
    }
    result += '\n';
    return result;
}

template<class T>
void ArrayBag<T>::operator+=(const ArrayBag<T>& a_bag)
{
    for (int i = 0; i < a_bag.item_count_; i++)
    {
        add(a_bag.items_[i]);
    }
}

template<class T>
void ArrayBag<T>::operator-=(const ArrayBag<T>& a_bag)
{
    for (int i = 0; i < a_bag.item_count_; i++)
    {
        remove(a_bag.items_[i]);
    }
}

template<class T>
void ArrayBag<T>::operator/=(const ArrayBag<T>& a_bag)
{
    int i = 0;
    while (i < item_count_)
    {
        if (!a_bag.contains(items_[i]))
        {
            remove(items_[i]);
        }
        else
        {
            i++;
        }
    }
}




// ********* PRIVATE METHODS **************//

/**
 @param target to be found in items_
 @return either the index target in the array items_ or -1,
 if the array does not containthe target.
 **/
template<class T>
int ArrayBag<T>::getIndexOf(const T& target) const
{
    bool found = false;
   int result = -1;
   int search_index = 0;

   // If the bag is empty, item_count_ is zero, so loop is skipped
   while (!found && (search_index < item_count_))
   {
      if (items_[search_index] == target)
      {
         found = true;
         result = search_index;
      }
      else
      {
         search_index++;
      }  // end if
   }  // end while

   return result;
}  // end getIndexOf```


#ifndef ZOO_RECORD_HPP
#define ZOO_RECORD_HPP

#include "ArrayBag.hpp"
#include "Animal.hpp"
#include <fstream>
#include <sstream>

class ZooRecord : public ArrayBag<Animal>
{
public:
    //default constructor for empty record
    ZooRecord();
    
    /**parameterized constructor
     @pre the input file is expected to be in CSV
     (comma separated value) format as: 
    "animal_name,hair,feathers,eggs,milk,airborne,aquatic,predator,toothed,
    backbone,breathes,venomous,fins,legs,tail,domestic,catsize,class_type\n"
     @param input_file_name the name of the input file
     @post adds Animal objects to record as per the data in the input file
    **/
    ZooRecord(std::string input_file_name);

    /**@post displays all animals in record, one per line by calling animal's 
    display method” **/
    void display();
};
#endif
#include "ZooRecord.hpp"

//default constructor for empty record
ZooRecord::ZooRecord()
{
    //default constructor for ArrayBag is called automatically
}

/**parameterized constructor
 @pre the input file is expected to be in CSV
 (comma separated value) format as: 
"animal_name,hair,feathers,eggs,milk,airborne,aquatic,predator,toothed,
backbone,breathes,venomous,fins,legs,tail,domestic,catsize,class_type\n"
 @param input_file_name the name of the input file
 @post adds Animal objects to record as per the data in the input file
 **/
ZooRecord::ZooRecord(std::string input_file_name)
{
    std::ifstream input_file(input_file_name);
    std::string line;
    while(std::getline(input_file,line))
    {
        std::stringstream line_stream(line);
        std::string cell;
        std::getline(line_stream, cell, ',');
        std::string name = cell;
        //parse remaining cells and set values for domestic and predator
        bool domestic, predator;
        std::getline(line_stream, cell, ',');
        domestic = cell == "1";
        std::getline(line_stream, cell, ',');
        predator = cell == "1";
        //create a new animal object with the parsed data
        Animal new_animal(name,domestic,predator);
        // add the new animal to the record
        add(new_animal);
    }
}

/**@post displays all animals in record, one per line by calling animal's 
 display method” **/
void ZooRecord::display()
{
    for(int i = 0; i < item_count_; i++)
    {
        items_[i].display();
    }
}

However, when compiling I get this error:

ZooRecord.cpp:4: undefined reference to ArrayBag<Animal>::ArrayBag()' c:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\super\AppData\Local\Temp\ccaUMYah.o: in function ZooRecord::ZooRecord(std::__cxx11::basic_string<char, std::char_traits, std::allocator >)': ZooRecord.cpp:17: undefined reference to ArrayBag<Animal>::ArrayBag()' c:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ZooRecord.cpp:36: undefined reference to ArrayBag::add(Animal const&)' collect2.exe: error: ld returned 1 exit status

I expected the program to compile correctly but I kept getting the undefined reference issue even though I thought it was defined.

I compiled this on vsc using g++.exe build active file. I dont understand why it's giving me undefined reference, does it have something to do with changing T to Animal in the derived class? Please help.

  • Members of templates must be defined in the header file (except when using the explicit instantiation mechanism). So move everything from `ArrayBag.cpp` to the end of `ArrayBag.hpp` (but before the `#endif` of the header guard). – user17732522 Jan 20 '23 at 05:44

0 Answers0