4

As the title says, one part of my assignment is to implement an array class. The professor gave us the header style to start off with, creating the function declarations for us. Using previous examples, I've tried my best to define these functions, but I'm having a lot of trouble understanding just what's going on. It might be a little much to post an entire header file, but I'll try to explain the issues I'm having regardless. Here is my code:

#ifndef ARRAY_H
#define ARRAY_H
#include <iostream>
#include <string>
using namespace std;

template <class T>
class Array {
private:
    int size;
    T * arr;
public:
    int getSize();

    Array();
    Array(int size);
    Array(Array & other);
    Array(T[], int n);
    ~Array();
    Array & operator=(Array & rhs);
    Array & operator+(Array & rhs); // append
    T & operator[](int i); //allow read and write
    const T & operator[](int n) const; // readonly
    void print(int n = 5);
    void print(ostream & out, int n);
    operator int *() { return arr; }
    friend ostream & operator <<(ostream & out, Array <T>& rhs);
};

template <class T>
int Array<T>::getSize() {
    return size;
}

template <class T>
Array<T>::Array() {
    arr = new T[];
}

template <class T>
Array<T>::Array(int size) {
    arr = new T[size];
}

template <class T>
Array<T>::Array(Array & other) {
    size = other.getSize();
    arr = new T[size];
    copy(arr[0], arr[size + 1], other.arr[0]);
}

template <class T>
Array<T>::Array(T[], int n) {
    size = n;
    arr = new T[n];
}

template <class T>
Array<T>::~Array() {
    if (arr) {
        delete arr;
    }
}

template <class T>
Array<T>& Array<T>::operator=(Array & rhs) {
    if (this != &rhs) {
        delete[] arr;
        size = rhs.getSize();
        arr = new T[size];
        copy(arr[0], arr[size+1], rhs.arr[0]);
    }
    return *this;
}

template <class T>
Array<T>& Array<T>::operator+(Array & rhs) {
    Array *tmp;

    tmp = new Array(size + rhs.getSize());
    return *tmp;
}

template <class T>
T& Array<T>::operator[](int i) {
    assert(0 <= i && i < size);
    return arr[i];
}

template <class T>
const T& Array<T>::operator[] (int n) const {
    assert(0 <= i && i < size);
    return arr[i];
}

template <class T>
void Array<T>::print(ostream &out, int n) {
    for (size_t i = 0; i < n; i++) {
        out << arr[i] << " ";
    }
}

template <class T>
void Array<T>::print(int n = 5) {
     print(cout, n);
}

template <class T>
ostream & operator << (ostream & out, Array<T> & rhs) {
    out << "( " << rhs.getSize() << ")";
    return out;
}

#endif

I'd appreciate any and all hints, just to help me figure out what's going on in just this class. I'm sorry if this ends up being a lot to ask for.

Edit: Thank you all for the help again! The linker errors were fixed. I should've specified that print were the members of the class, instead of just being free.

14
  • The strcpy function is tailored to copy strings, not general data. You might want to use std::memcpy (or std::copy). Commented Nov 18, 2013 at 8:46
  • You probably want to use memcpy instead of strcpy for point 1 & 2 Commented Nov 18, 2013 at 8:46
  • There are also some other problems with your code, like the return type Array<T>::T for the operator[] functions. Commented Nov 18, 2013 at 8:51
  • I made the changes for 1 and 2, so strcpy(arr, other.arr); is now memcpy(arr, rhs.arr, sizeof(arr));. No more errors from that come up. For the operator[] functions, do I need to return an array of the template class? Commented Nov 18, 2013 at 9:08
  • 1
    Please post the code to this site, rather than using an external link. Also, fix your IDE so that tab inserts spaces when you indent, and preferably use either 2 or 4 spaces. Commented Nov 18, 2013 at 9:35

1 Answer 1

2
  1. When trying to do a copy constructor for Array(Array & other); on line 46, I get the error error C2664: 'char *strcpy(char *,const char *)' : cannot convert argument 1 from 'int *' to 'char *' It keeps pointing to the strcpy function, but I'm not sure what it's asking me to change. I get two errors for the same line, the second of which says cannot convert argument 1 from 'std::string *' to 'char *'

The problem here is that strcpy is meant to copy char types between two memory locations. However, your template argument T could be any type really and so use of strcpy here is rather inappropriate if you're going for genericity. A straight-forward(but not very efficient) implementation for your copy constructor would be something like:

template <class T>
Array<T>::Array(const Array &other) : size(other.size), arr(new T[size])
{
  for (int i = 0; i < size; ++i)
    arr[i] = other.arr[i];
}

2) I get another error with trying to strcpy function on line 71 when writing the operator= overloader. It tells me cannot convert argument 1 from 'std::string *' to 'char *'

Again, it's the same problem as one: older C-style str* functions work with raw char * pointers to some chunk of memory containing characters. As such, these groups of functions cannot directly work with std::string from the standard c++ library without some adaptation. Mostly of the time you don't want to do this because those functions can mutate std::string without preserving its internal invariants which is dangerous.

For the assignment operator, you can just do a copy and swap:

template <class T>
Array<T>& Array<T>::operator = (Array rhs)
{
  std::swap(size, rhs.size);
  std::swap(arr, rhs.arr);
  return *this;
}

3) For the T & operator[](int i); //allow read and write on line 85, I'm wondering if I'm supposed to create a new array with i slots. The allow, read, and write comment the professor left confused me. Also, for the following function, Array<T>::T & operator[] (int n) const; the comment said read only, so I assumed I was just supposed to return the array with n items.

The operator [] is for providing syntactic sugar for accessing a specific item in your Array<T> given some index i. Without it the following wouldn't work:

Array<int> arr(42);
std::cout << arr[0];

As such, you shouldn't have to allocate anything inside this operator. You can implement both const and non-const version in the same way. Only difference is one will have a const qualifier at the end so this will work with const Array<T> also:

template <class T>
T& Array<T>::operator[] (int i) 
{
  assert(0 <= i && i < size);
  return arr[i];
}

template <class T>
const T& Array<T>::operator[] (int i) const
{
  assert(0 <= i && i < size);
  return arr[i];
}

4) I left a comment for the void print(int n = 5); function. But to summarize, I want to be able to print out a certain number of items in the array per line, but there's no multidimensional array. I attempted two for loops, but it just got stuck on the same array item.

5) I'm not sure why void print(ostream & out, int n); is needed. Is it supposed to override the above print statement?

The proper terminology you're looking for is "overloading". "overriding" has a very specific meaning in C++ nomenclature which doesn't apply in this scenario.

Judging from the declaration, it seems the intent for the second print signature is to support different kinds of output stream (of which cout is one type btw). What you'd want to do here is to implement the first version of print in terms of the second one. In fact, they don't even need to be template functions at all:

void print(ostream &out, int n)
{
  for (size_t i = 0; i < n; ++i)
    out << pets[i] << " ";
}

void print(int n)
{
  print(cout, n);
}

Note, print should probably be modified to take the array to print out rather than referring to one (global?) particular instance here.

Edit: When modifying print to take the array to print it will of course have to be a template. One possible signature:

  template <typename T>
  void print(const Array<T> &arr, int n)
  {
    print(arr, n, cout);
  }
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the help. I removed the template function lines for the print functions, but it just brought up other errors, like the array being undeclared. Would this mean that it's absolutely necessary to have these? Every other change worked just fine, though. Edit: Also, strangely enough, after fixing the code, I now have linker errors..
You can change the signature to something like template <typename T> void print(const Array<T> &arr, int n, ostream &out);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.