0

I'm learning C++ in a class. They have us using Geany on a Virtual Machine with Ubuntu. I miss the powers of an IDE, so I tried several: Netbeans, Eclipse and Code::Blocks.

The code I have for a homework compiles and runs with no problems in Geany on the VM. When I tried all the other IDEs, the compiler gives me an error. I tried Netbeans and Eclipse on Windows 7 and Ununtu in the same VM. In searching for an answer, this help topic says that Geany is doing a lot behind the scenes for me. So I've tried playing with removing the various #include statements I have for the headers and source codes, and solved the problem (Just kidding!) and can't figure out what's really happening.

ArrayBagTester2.cxx: (this is what I compile/run in Geany)

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

using namespace std;

int main()
    {
        // a bunch of stuff
    }

ArrayBag.h: (provided by the professor with no changes made/needed)

#ifndef _ARRAY_BAG
#define _ARRAY_BAG

#include "BagInterface.h"
template<class ItemType>
class ArrayBag : public BagInterface<ItemType>
{
    private:
        static const int DEFAULT_CAPACITY = 4;
        ItemType* itemArray; //array must be dynamic; so pointers are very yes
        int numberOfItems;
        int myCapacity; //added variable to track capacity

    public:
        ArrayBag(int capacity = DEFAULT_CAPACITY); // new constructor
        ArrayBag(const ArrayBag& anotherBag); // copy constructor
        ~ArrayBag(); //destructor
        int getCurrentSize() const;
        int getCapacity() const;
        void resize(int newCapacity); // resize
        bool isEmpty() const;
        bool isFull() const;
        bool add(const ItemType& newEntry);
        bool remove(const ItemType& anEntry);
        void clear();
        bool contains(const ItemType& anEntry) const;
        int getFrequencyOf(const ItemType& anEntry) const;
        vector<ItemType> toVector() const;
        ArrayBag& operator=(const ArrayBag& anotherBag);
};

#include "ArrayBag.cxx"
#endif

BagInterface.h (Provided by text book author, note copyright. I have crippled to maintain their copyright.)

//  Created by Frank M. Carrano and Tim Henry.
//  Copyright (c) 2013 __Pearson Education__. All rights reserved.

/** Listing 1-1.
    @file BagInterface.h */
#ifndef _BAG_INTERFACE
#define _BAG_INTERFACE

#include <vector>
using namespace std;

template<class ItemType>
class BagInterface
{
public:
   virtual .... stuff here, all virtual functions ...
};
#endif

ArrayBag.cxx: The meat and potatoes and what we're supposed to (solely) edit, errors start at line 9:

#include <vector>
#include <cstddef>
#include <algorithm>

#include "ArrayBag.h"

// Constructor; creates and initializes an empty Bag of "capacity" size
template <class ItemType>
********************//LINE 9:**************************
ArrayBag<ItemType>::ArrayBag(int capacity)
{
    myCapacity = capacity;
    itemArray = new ItemType[myCapacity];
    numberOfItems = 0;
}

// Copy constructor; creates and initializes Bag from another Bag
template <class ItemType>
ArrayBag<ItemType>::ArrayBag(const ArrayBag& anotherBag)
{
    numberOfItems = anotherBag.getCurrentSize();
    myCapacity = anotherBag.getCapacity();
    itemArray = new ItemType[myCapacity];

    for (int i = 0; i < numberOfItems; ++i)
        itemArray[i] = anotherBag.itemArray[i];
}

//destructor
template <class ItemType>
ArrayBag<ItemType>::~ArrayBag()
{
    delete [] itemArray;
}

// Assignment operator
template <class ItemType>
ArrayBag<ItemType>& ArrayBag<ItemType>::operator=(const ArrayBag<ItemType>& anotherBag)
{
    // see if we're trying to assign to ourself, stupid user
    if (&anotherBag == this)
        return *this;
    clear();
    //ArrayBag<ItemType>::~ArrayBag();
    delete [] itemArray;
    //ArrayBag<ItemType>::ArrayBag(anotherBag);
    numberOfItems = anotherBag.getCurrentSize();
    myCapacity = anotherBag.getCapacity();
    itemArray = new ItemType[myCapacity];

    for (int i = 0; i < numberOfItems; ++i)
        itemArray[i] = anotherBag.itemArray[i];

    return *this;
}

// Return the number of Items being stored in the Bag
template <class ItemType>
int ArrayBag<ItemType>::getCurrentSize() const
{
    return numberOfItems;
}

// Return the capacity of the bag (the maximum Items it can store)
template <class ItemType>
int ArrayBag<ItemType>::getCapacity( ) const
{
    return myCapacity;
}

//Resizes the bag's capacity to newCapacity
//if the new size is larger, copy all bag contents
// we don't downsize a bag in HW2
template <class ItemType>
void ArrayBag<ItemType>::resize(int newCapacity)
{
    ItemType* oldArray = itemArray;
    itemArray = new ItemType[newCapacity];
    for(int i = 0; i < myCapacity; ++i)
        itemArray[i] = oldArray[i];
    delete [] oldArray;
}

// Report whether the Bag is empty
// Return true if the Bag is empty (storing no Items);
// Return false if Items exist in the Bag
template <class ItemType>
bool ArrayBag<ItemType>::isEmpty() const
{
    return (numberOfItems == 0);
}

// Report whether the Bag is full
// Return true if the Bag is filled to capacity
// Return false if there is still room
template <class ItemType>
bool ArrayBag<ItemType>::isFull() const
{
    //This bag is resizeable, so it's never full
    return false;
}

// Give the Bag a new Item to store
// If Bag is full, double capacity and add newItem
// Else, Bag must add this Item to its Item array and update its numberOfItems
// If Bag is full after this, return true; else return false
template <class ItemType>
bool ArrayBag<ItemType>::add(const ItemType& newItem)
{
    if (numberOfItems == myCapacity)
    {
        resize(myCapacity * 2);
        myCapacity = myCapacity * 2;
    }

    itemArray[numberOfItems++] = newItem;

    //This bag is resizeable, so it's never full
    return false;
}

// Make the Bag act like an empty Bag again
template <class ItemType>
void ArrayBag<ItemType>::clear()
{
    numberOfItems = 0;
}

// Remove an Item from the bag
// If Item is not there, nothing changes and we return false
// Else, we fill in its spot in that Item array and count number of Items down
template <class ItemType>
bool ArrayBag<ItemType>::remove(const ItemType& anItem)
{
    for (int i = 0; i < numberOfItems; ++i)
    {
        if (itemArray[i] == anItem)
        {
            itemArray[i] = itemArray[--numberOfItems];
            return true;
        }
    }
    return false;
}

// Check if an Item is in the Bag
// Return true if it is in the Bag, and false if not
template <class ItemType>
bool ArrayBag<ItemType>::contains(const ItemType& anItem) const
{
    for (int i = 0; i < numberOfItems; ++i)
        if (itemArray[i] == anItem) return true;
    return false;
}

// Check how many times an Item is in the Bag
// return 0 if it's not there; otherwise,
// return the number of times it occurs
template <class ItemType>
int ArrayBag<ItemType>::getFrequencyOf(const ItemType& anItem) const
{
    int frequency = 0;

    for (int i = 0; i < numberOfItems; ++i)
        if (anItem == itemArray[i]) ++frequency;

    return frequency;
}

// Make an output vector of Items from the bag (for checking)
template <class ItemType>
vector<ItemType> ArrayBag<ItemType>::toVector() const
{
    vector<ItemType> bagContents;

    for (int i = 0; i < numberOfItems; ++i)
        bagContents.push_back(itemArray[i]);

    return bagContents;
}

Here is the error generated for each method in the ArrayBag.cxx:

C:\Users...\HW2\ArrayBag.cxx|9|error: redefinition of 'ArrayBag::ArrayBag(int)'| C:\Users...\HW2\ArrayBag.cxx|9|error: 'ArrayBag::ArrayBag(int)' previously declared here

... Truncated for clarity ...

I would like to understand:

  1. Why does Geany work when the others do not? What really is that make makefile magic?
  2. Is there an (easy) fix to Netbeans (not that Netbeans is causing the problem) on Windows to fix this? (I seem to prefer Netbeans, no other reason.) or:
  3. What is a more traditional or standard way of including these relationships and files?
Jason Aller
  • 3,541
  • 28
  • 38
  • 38
MECU
  • 770
  • 1
  • 11
  • 25
  • How do you compile those files ? – hivert Feb 06 '14 at 22:44
  • 1
    Instead of this monstrousity of code, why not a simple "Hello World" program to test these various IDE's? – PaulMcKenzie Feb 06 '14 at 22:47
  • @hivert In Geany, I click the Bookshelf icon, and then the gears icon. The command window has `g++ -Wall -g -o "%e" "%f"` is the Build command in Geany. – MECU Feb 06 '14 at 22:48
  • @PaulMcKenzie Hello World's do compile/run fine on all. This monstrosity of code is the problem. – MECU Feb 06 '14 at 22:48
  • 1
    It could be that some compilers attempt to compile `ArrayBag.cxx`, which is not meant to be compiled. But I wouldn't trust code with reserved names and `using namespace std` in header files. – juanchopanza Feb 06 '14 at 22:49
  • MECU: I don't need the compile command which works but the one which doesn't ;-) – hivert Feb 06 '14 at 22:50
  • #include int main() { std::cout << "Hello World"; } Right there, you are testing the include paths, whether you're using a compliant compiler underneath the hood, etc. No need for anything more than this to test if your IDE is acting right. – PaulMcKenzie Feb 06 '14 at 22:50
  • @hivert `mingw32-g++.exe -Wall -fexceptions -g -c C:\Users\...\HW2\ArrayBag.cxx -o obj\Debug\ArrayBag.o` – MECU Feb 06 '14 at 22:51
  • @PaulMcKenzie Hello World's compile and run fine. The IDE is therefore not the problem, this code and something "specialized" with Geany are the problem. – MECU Feb 06 '14 at 22:52
  • The g++ compiler works the same in all enviroments. IDE's don't do anything except spawn g++ with the appropriate command-line arguments. If your IDE didn't set the #include paths correctly, then again, a simple Hello World program and not much more than that can isolate the problem. – PaulMcKenzie Feb 06 '14 at 22:53

2 Answers2

1

The file ArrayBag.cxx is included (which is very strange way of doing it but whatever) and is not meant to be compiled. Just compile ArrayBagTester2.cxx and it should be ok.

By the way: I agree with the previous comment that this thing is a monstrosity...

hivert
  • 10,579
  • 3
  • 31
  • 56
  • I found an option in Code::Blocks to tell it that the ArrayBag.cxx file should not be compiled. It didn't compile the .h files (automatically set that). It works fine now. – MECU Feb 06 '14 at 22:59
  • Do you have an answer on how to better include or a more standard way to include these? I'm just learning what the class teaches. – MECU Feb 06 '14 at 23:00
1

You shouldn't be compiling ArrayBag.cxx as a separate compilation unit. See here:

Why can templates only be implemented in the header file?

Template implementation files are not separate compilation units, but your command-line suggests that it was compiled as one.

Community
  • 1
  • 1
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45