Getting error in merging two arrays in c++? - c++

I am trying to merge two dynamic arrays but I am getting an error in my merge function that
"data': is not a member of 'List<T>"
I know that the error is ocuring because the given parameter in the merge(const List& other) is list but I am confused how to access my ArrayList2 which has been passed in merge function in the main
my code is:
#include <iostream>
using namespace std;
template<class T>
class List {
public:
// return the capacity of the list
virtual size_t capacity() const = 0;
// return the number of elements in the list
virtual size_t size() const = 0;
// inserts an element to the beginning
virtual void push_front(const T& value) = 0;
// adds an element to the end
virtual void push_back(const T& value) = 0;
// removes the last element
virtual void pop_back() = 0;
// removes the first element
virtual void pop_front() = 0;
// remove the first occurrence of an element with the given value
virtual void remove(const T& val) = 0;
// merges two sorted lists
virtual void merge(const List<T>& other) = 0;
virtual ~List() {}
};
template<class T>
class ArrayList : public List<T>
{
private:
T* data;
size_t max_capacity;
size_t num_of_element;
public:
ArrayList() = delete; // disable default constructor
// constructor
ArrayList(size_t capacity) : max_capacity(capacity), num_of_element(0) {
data = new T[capacity];
}
// copy constructor
ArrayList(const ArrayList<T>& other_list) : max_capacity(other_list.max_capacity),
num_of_element(other_list.num_of_element) {
data = new T[max_capacity];
for (size_t i = 0; i < other_list.num_of_element; i++) {
data[i] = other_list.data[i];
}
}
// destructor
virtual ~ArrayList() {
delete[]data;
}
size_t capacity() const override {
return max_capacity;
}
size_t size() const override {
return num_of_element;
}
T& operator[](int index) {
return data[index];
}
bool operator==(const ArrayList<T>& other_list) {
// not comparing capacity as eventually array list can be made capacity irrelevant using dynamic allocation
if (num_of_element != other_list.num_of_element) {
return false;
}
for (int i = 0; i < num_of_element; i++) {
if (data[i] != other_list.data[i]) {
return false;
}
}
return true;
}
void push_front(const T& value)
{
}
void push_back(const T& value)
{
if (max_capacity > num_of_element)
{
num_of_element++;
data[num_of_element - 1] = value;
}
}
void pop_back()
{
}
void pop_front()
{
}
void remove(const T& val)
{
int i = 0, j;
while (i < max_capacity)
{
if (data[i] == val)
{
for (int j = i; j < num_of_element-1; j++)
data[j] = data[j + 1];
if (data[i] == val && (i + 1) > num_of_element - 1)
{
data[i] = {};
num_of_element--;
break;
}
num_of_element--;
}
else
i++;
}
}
void merge(const List<T>& other)
{
int i;
int newsize = size() + other.size();
T* temp = new T[newsize];
for (i = 0; i < num_of_element; i++)
temp[i] = data[i];
for (int j = 0; j < other.size(); j++)
{
temp[i] = other.data[j]; //I am getting error on this line
i++;
}
}
private:
void shift_left_to(size_t start) {
for (size_t i = start; i < num_of_element - 1; i++) {
data[i] = data[i + 1];
}
}
};
int main() {
ArrayList<int> list1(3);
list1.push_back(3);
list1.push_back(1);
list1.push_back(1);
ArrayList<int> list2(2);
list2.push_back(1);
list2.push_back(8);
list1.merge(list2);
/* for (size_t i = 0; i < list1.size(); i++)
cout<<list1[i]<<" ";
cout<<"Size:"<<list1.size()<<" Capacity:"<<list1.capacity();*/
system("pause");
return 0;
}

Presumably, all of your concrete List<T> classes (e.g. ArrayList<T>) will have some kind of accessors to the elements. You can make those accessors part of the List<T> interface and call them in the implementation of void merge(List<T> const&). As an example:
template <class T>
class List {
public:
// ...
virtual T& operator[](int index) = 0;
virtual T const& operator[](int index) const = 0;
};
template <class T>
class ArrayList : public List<T> {
private:
T* data;
size_t max_capacity;
size_t num_of_element;
public:
// ...
T& operator[](int index) override { return data[index]; }
T const& operator[](int index) const override { return data[index]; }
// ...
void merge(const List<T>& other) {
int i;
int newsize = size() + other.size();
T* temp = new T[newsize];
for (i = 0; i < num_of_element; i++) temp[i] = data[i];
for (int j = 0; j < other.size(); j++) {
temp[i] = other[j]; // < Use your List<T>::operator[] here
i++;
}
}
// ...
};

I'd say the message is quite descriptive: List does not have a member called data. You should use the [] operator instead to access the list elements in the merge function. [] operator is implemented by descendants of List.
temp[i] = other[j]

Related

Sorting a ring buffer class objects

I am trying to make a sorting function for a ring buffer class object, but it gives me the below error and I couldn't remove it:
template placeholder type 'ring' must be followed by a simple declarator-id
argument list for class template "ring" is missing
'arr' was not declared in this scope
(arr) was declared in the parameter of the function but yet it does not recognize it
hopefully someone can explain what is wrong with the sorting function, here is below my code:
#include<iostream>
#include<initializer_list>
template<typename T>
void swap(T& x, T& y) {
T temp;
temp = x;
x = y;
y = temp;
}
template<typename T>
class ring {
public:
class iterator;
public:
ring(std::initializer_list<T>elements) {
sze = elements.size();
value = new T[sze];
for (auto& i : elements) {
add(i);
}
}
T& get(int x) { return value[x]; }
std::size_t size() { return sze; }
void add(T v) {
value[index++] = v;
if (index == sze)
index = 0;
}
iterator begin() { return iterator(0, *this); }
iterator end() { return iterator(sze, *this); }
friend void BubbleSort(ring& arr, std::size_t n);
~ring() { delete[] value; }
private:
int index = 0;
std::size_t sze;
T* value;
};
template<typename T>
class ring<T>::iterator {
public:
iterator(int x, ring& y) :index(x), obj(y) {}
iterator& operator++() { index++; return *this; }
iterator& operator++(int x) { index++; return *this; }
bool operator!=(const iterator& other) { return index != other.index; }
T& operator*() { return obj.get(index); }
private:
int index;
ring& obj;
};
template<typename T>
void BubbleSort(ring& arr, std::size_t n) { // here is the function of the sorting.
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr.value[j] > arr.value[j + 1]) {
swap(arr.value[j], arr.value[j + 1]);
}
}
}
}
Your friendly compiler showed you already the problem and in which line it happened.
And it gave you 3 error messages telling you exactly what the problem is.
See my compiler output
Your class ring needs a template parameter. So same as in line 49 of the picture.
The below will compile.
#include<iostream>
#include<initializer_list>
template<typename T>
void swap(T& x, T& y) {
T temp;
temp = x;
x = y;
y = temp;
}
template<typename T>
class ring {
public:
class iterator;
public:
ring(std::initializer_list<T>elements) {
sze = elements.size();
value = new T[sze];
for (auto& i : elements) {
add(i);
}
}
T& get(int x) { return value[x]; }
std::size_t size() { return sze; }
void add(T v) {
value[index++] = v;
if (index == sze)
index = 0;
}
iterator begin() { return iterator(0, *this); }
iterator end() { return iterator(sze, *this); }
friend void BubbleSort(ring& arr, std::size_t n);
~ring() { delete[] value; }
private:
int index = 0;
std::size_t sze;
T* value;
};
template<typename T>
class ring<T>::iterator {
public:
iterator(int x, ring& y) :index(x), obj(y) {}
iterator& operator++() { index++; return *this; }
iterator& operator++(int x) { index++; return *this; }
bool operator!=(const iterator& other) { return index != other.index; }
T& operator*() { return obj.get(index); }
private:
int index;
ring& obj;
};
template<typename T>
void BubbleSort(ring<T>& arr, std::size_t n) { // here is the function of the sorting.
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr.value[j] > arr.value[j + 1]) {
swap(arr.value[j], arr.value[j + 1]);
}
}
}
}
I did not check the functionality. Sorting a ringbuffer sounds somehow strange . . .

How to implemet copy constructor in C++

this is the header of a class that I have been designing for an assignment. I have included constructors, a destructors, as well as overloaded operators. Could you give me a hint how to properly define the constructors in a class using c++ 20 most recent features in an efficient way.
#ifndef VECTOR_DOUBLE_H
#define VECTOR_DOUBLE_H
#include <memory>
#include <vector>
class vector_double {
public:
vector_double(int size);
vector_double(std::initializer_list<double> lst);
vector_double(const double* array, int size);
vector_double(const vector_doubler& other);
vector_doubleoperator=(const vector_double& other);
// because I use a managed pointer I don't need a destructor
~vector_double() noexcept = default;
void set(int index, double val);
double& get(int index);
const double& get(int index) const;
int size() const;
void reset(double val);
void fill_from(std::initializer_list<double> lst);
void fill_from(const double* array, int size);
int copy_to(std::vector<double>& vec) const;
double& operator[](int index);
const double& operator[](int index) const;
operator double() const;
vector_double add(const vector_double& other) const;
vector_doubleadd(double number) const;
vector_doublemul_by(double number) const;
void resize(int size);
friend std::ostream& operator<<(std::ostream& out, const vector_double& vec);
private:
std::unique_ptr<double[]> m_array;
int m_size;
};
inline std::ostream& operator<<(std::ostream& out, const vector_double& vec){
if (vec.m_size == 0){
out << "{ }";
}
else{
auto first = true;
out << '{';
for (int i=0; i < vec.m_size; ++i){
if (!first)
out << ", ";
else
first = !first;
out << vec.m_array[i];
}
out << '}';
}
return out;
}
#endif //VECTOR_DOUBLE_H
This example definition may help, I tried sticking to C++20 features:
#include <cmath>
#include "vector_double.h"
vector_double::vector_double(int size):
m_array{ new double[size] },
m_size{size}
{}
vector_double::vector_double(std::initializer_list<double> lst): //Constructor that takes an init list
vector_double(lst.size())
{
std::copy(lst.begin(), lst.end(), m_array.get());
}
vector_double::vector_double(const double* array, int size): //Constructor that takes array and size
vector_double(size)
{
// std::copy(array, array + size, m_array.get());
std::copy(&array[0], &array[size], m_array.get());
}
vector_double::vector_double(const vector_double& other): //Copy Constructor
vector_double(other.m_size)
{
std::copy(&other.m_array[0], &other.m_array[m_size], &m_array[0]);
}
vector_double& vector_double::operator=(const vector_double& other) {
if (this != &other) {
if (m_size != other.m_size) {
auto* array = new double[other.m_size];
m_array.reset(array);
m_size = other.m_size;
}
std::copy(&other.m_array[0], &other.m_array[m_size], &m_array[0]);
}
return *this;
}
void vector_double::set(int index, double val) {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
m_array[index] = val;
}
double& vector_double::get(int index) {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
return m_array[index];
}
const double& vector_double::get(int index) const {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
return m_array[index];
}
int vector_double::size() const {
return m_size;
}
void vector_double::reset(double val) {
for (int i=0; i<m_size; ++i){
m_array[i] = val;
}
}
void vector_double::fill_from(std::initializer_list<double> lst) {
int size = std::min((int)lst.size(), m_size);
std::copy(lst.begin(), lst.begin() + size, &m_array[0]);
}
void vector_double::fill_from(const double* array, int size) {
size = std::min(size, m_size);
for (int i = 0; i < size; ++i) {
m_array[i] = array[i];
}
}
int vector_double::copy_to(std::vector<double>& vec) const {
for (int i = 0; i < m_size; ++i) {
vec.push_back(m_array[i]);
}
return m_size;
}
double& vector_double::operator[](int index) {
return m_array[index];
}
const double& vector_double::operator[](int index) const { //Overloading "[]" operator
return m_array[index];
}
vector_double::operator double() const {
double sum = 0.0;
for (int i = 0; i < m_size; ++i) {
sum += m_array[i] * m_array[i];
}
return std::sqrt(sum);
}
vector_double vector_double::add(const vector_double& other) const {
if (m_size != other.m_size)
throw std::logic_error("size mismatch");
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] += other[i];
}
return copy;
}
vector_double vector_double::add(double number) const {
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] += number;
}
return copy;
}
vector_double vector_double::mul_by(double number) const {
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] *= number;
}
return copy;
}
void vector_double::resize(int size) {
if (size != m_size){
auto array = new double[size] {0,};
auto common = std::min(size,m_size);
for (int i = 0; i < common; ++i) {
array[i] = m_array[i];
}
m_array.reset(array);
m_size = size;
}
}

Still having an Unhandled Exception after editing it a bit

Inventory::Inventory()
{
this->cap = 10;
this->nrOfItems = 0;
this->itemArr = new Item* [cap]();
}
Inventory::~Inventory()
{
for (size_t i = 0; i < this->nrOfItems; i++)
{
delete this->itemArr[i];
}
delete[] this->itemArr;
}
void Inventory::expand()
{
this->cap *= 2;
Item **tempArr = new Item*[this->cap]();
for (size_t i = 0; i < this->nrOfItems, i++;)
{
tempArr[i] = new Item(*this->itemArr[i]);
}
for (size_t i = 0; i < this->nrOfItems, i++;)
{
delete this->itemArr[i];
}
delete[] this->itemArr;
this->itemArr = tempArr;
this->initialize(this->nrOfItems);
}
void Inventory::initialize(const int from)
{
for (size_t i = from; i < cap, i++;)
{
this->itemArr[i] = nullptr;
}
}
void Inventory::addItem(const Item& item)
{
if (this->nrOfItems >= this->cap)
{
expand();
}
this->itemArr[this->nrOfItems++] = new Item(item);
}
void Inventory::removeItem(int index)
{
}
Above is my code from Inventory.cpp and the issue is that I keep getting an Unhandled Exception from the line that has:
this->itemArr[i] = nullptr;
I have no idea where I'm messing up in the code. Below I am posting from Inventory.h:
class Inventory
{
private:
int cap;
int nrOfItems;
Item **itemArr;
void expand();
void initialize(const int from);
public:
Inventory();
~Inventory();
void addItem(const Item &item);
void removeItem(int index);
inline void debugPrint() const
{
for (size_t i = 0; i < this->nrOfItems; i++)
{
std::cout << this->itemArr[i]->debugPrint() << std::endl;
}
}
};
This is where itemArr should be housed but for some reason, it is not pulling. I am new to coding so I don't know all of the tips and tricks involved with it.
In the loop i < cap, i++;, you will first check if i is in bounds, and then increase it by one before the loop body executes. Thus if i=cap-1 the check will pass, i will become cap and you're out of bounds.
Instead write (size_t i = from; i < cap;i++), so that the increment of i is executed after the loop body.
A see several problems with your code:
In Inventory::expand(), since you are working with an array of pointers (why not an array of objects?), there is no need to make clones of the existing Item objects to the new array, just copy the existing pointers as-is. You are just expanding the array to fit more pointers, so the clones are wasted overhead. Not a fatal issue, but it is something you should be aware of.
In both Inventory::initialize() and Inventory::expand(), your loops are setup incorrectly. You are performing the i++ in the wrong place. Given this definition of a loop:
for ( <init-statement> <condition> ; <iteration_expression> )
You are performing the i++ as part of the <condition>, not the <iteration_expression>. A simply typo caused by you using the comma operator instead of ;, but an important typo nonetheless.
Inventory is violating the Rule of 3/5/0, by not implementing copy/move constructors and copy.move assignment operators.
With that said, try this instead:
class Inventory
{
private:
size_t cap;
size_t nrOfItems;
Item **itemArr;
void expand();
public:
Inventory();
Inventory(const Inventory &src);
Inventory(Inventory &&src);
~Inventory();
Inventory& operator=(Inventory rhs);
void addItem(const Item &item);
void removeItem(size_t index);
inline void debugPrint() const
{
for (size_t i = 0; i < nrOfItems; ++i)
{
std::cout << itemArr[i]->debugPrint() << std::endl;
}
}
};
Inventory::Inventory()
{
cap = 10;
nrOfItems = 0;
itemArr = new Item*[cap]();
}
Inventory::Inventory(const Inventory &src)
{
cap = src.cap;
nrOfItems = src.nrOfItems;
itemArr = new Item*[cap]();
for(size_t i = 0; i < nrOfItems; ++i)
{
itemArr[i] = new Item(*(src.itemArr[i]));
}
}
Inventory::Inventory(Inventory &&src)
{
cap = src.cap; src.cap = 0;
nrOfItems = src.nrOfItems; src.nrOfItems = 0;
itemArr = src.itemArr; src.itemArr = nullptr;
}
Inventory::~Inventory()
{
for (size_t i = 0; i < nrOfItems; ++i)
{
delete itemArr[i];
}
delete[] itemArr;
}
Inventory& Inventory::operator=(Inventory rhs)
{
Inventory temp(std::move(rhs));
std::swap(cap, temp.cap);
std::swap(nrOfItems, temp.nrOfItems);
std::swap(itemArr, temp.itemArr);
return *this;
}
void Inventory::expand()
{
size_t newCap = cap * 2;
Item **tempArr = new Item*[newCap]();
for (size_t i = 0; i < nrOfItems; ++i)
{
tempArr[i] = itemArr[i];
}
delete[] itemArr;
itemArr = tempArr;
cap = newCap;
}
void Inventory::addItem(const Item& item)
{
if (nrOfItems >= cap)
{
expand();
}
itemArr[nrOfItems] = new Item(item);
++nrOfItems;
}
void Inventory::removeItem(size_t index)
{
if (index < nrOfItems)
{
Item *item = itemArr[index];
for(size_t i = index + 1; i < nrOfItems; ++i)
{
itemArr[i-1] = itemArr[i];
}
--nrOfItems;
itemArr[nrOfItems] = nullptr;
delete item;
}
}
That being said, you really should be using std::vector instead, let it handle these details for you, eg:
#include <vector>
class Inventory
{
private:
std::vector<Item> itemVec;
public:
Inventory();
void addItem(const Item &item);
void removeItem(size_t index);
inline void debugPrint() const
{
for (Item &item : items)
{
std::cout << item.debugPrint() << std::endl;
}
}
};
Inventory::Inventory()
{
itemVec.reserve(10);
}
void Inventory::addItem(const Item& item)
{
itemVec.emplace_back(item);
}
void Inventory::removeItem(size_t index)
{
if (index < itemVec.size())
{
itemVec.erase(itemVec.begin() + index);
}
}
See how much simpler that is? :)

(c++) stl vector implemenation

I've implemented a simple vector-like structure
It works well if i use vector<int> or vector<char>
but when i use <vector<vector<int>> it makes error
Is there are good implementation code about vector stl or problem in my code?
here is my code
class _vector {
private:
int _size;
int _capacity;
T* vc;
public:
_vector(int size = 1) {
_size = 0;
_capacity = size;
vc = new T[size];
}
~_vector() {
delete[] vc;
}
int size() { return _size; }
bool empty() { return !_size; }
void resize(int size) {
_capacity = size;
T* tmp = new T[size];
for (int i = 0; i < _size; i++) tmp[i] = vc[i];
delete[] vc;
vc = tmp;
}
void clear() {
delete[] vc;
_capacity = 1;
_size = 0;
vc = new T[_capacity];
}
void push_back(T val) {
if (_size == _capacity) resize(2 * _capacity);
vc[_size++] = val;
}
void pop_back() {
if (_size == 0) return;
vc[--_size] = 0;
}
T& operator[](int i) const { return vc[i]; }
_vector<T>& operator=(_vector<T> &tmp) {
_capacity = tmp._capacity;
_size = tmp._size;
delete[] vc;
vc = new T[_capacity];
for (int i = 0; i < _size; i++) vc[i] = tmp[i];
return *this;
}
Your implementation is not following the Rule of 3, as it is missing a copy constructor, and a proper copy assignment operator (which can be implemented utilizing the copy constructor). And in C++11 and later, the Rule of 5, by adding a move constructor and a move assignment operator.
Also, your implementation does not work correctly with non-trivial types that have constructors/destructors defined, such as when T is another _vector type, or any other type that has pointers/resources allocated inside of it. So, your class needs to construct new objects when adding elements to the array, using placement-new, and destruct objects when removing elements from the array, by directly calling their destructors.
Try something more like this instead:
template <typename T>
class _vector {
public:
typedef unsigned int size_type;
typedef T value_type;
private:
size_type _size;
size_type _capacity;
value_type* vc;
public:
_vector(size_type initalcap = 0) : _size(0), _capacity(0), vc(0) {
reserve(initialcap);
}
_vector(const _vector<T> &src) : _size(0), _capacity(0), vc(0) {
reserve(src._capacity);
for(size_type i = 0; i < src._size; ++i) {
new(vc[i]) value_type(src.vc[i]);
}
_size = src._size;
}
// C++11 and later only...
_vector(_vector<T> &&src) : _size(src._size), _capacity(src._capacity), vc(src._vc) {
src._size = 0;
src._capacity = 0;
src.vc = 0;
}
~_vector() {
clear();
delete[] reinterpret_cast<char*>(vc);
}
size_type size() const { return _size; }
size_type capacity() const { return _capacity; }
bool empty() const { return !_size; }
void reserve(size_type newcap) {
if (newcap <= _capacity) return;
value_type* tmp = reinterpret_cast<value_type*>(new char[sizeof(value_type) * newcap]);
for (size_type i = 0; i < _size; ++i) {
new(tmp[i]) value_type(vc[i]);
}
delete[] reinterpret_cast<char*>(vc);
vc = tmp;
_capacity = newcap;
}
void resize(size_type newsize) {
if (newsize < _size) {
for(size_type i = _size; i-- > newsize; ) {
vc[i].~value_type();
}
_size = newsize;
}
else if (newsize > _size) {
reserve(newsize);
for (size_type i = _size; i < newsize; ++i) {
new(vc[i]) value_type();
}
_size = newsize;
}
}
void clear() {
resize(0);
}
void push_back(const T &val) {
if (_size == _capacity) reserve(2 * _capacity);
new(vc[_size]) value_type(val);
++_size;
}
void pop_back() {
if (_size) {
vc[--_size].~value_type();
}
}
value_type& operator[](size_type i) { return vc[i]; }
const value_type& operator[](size_type i) const { return vc[i]; }
_vector<T>& operator=(const _vector<T> &rhs) {
if (&rhs != this) {
_vector<T> tmp(rhs);
std::swap(tmp.vc, vc);
std::swap(tmp._size, _size);
std::swap(tmp._capacity, _capacity);
}
return *this;
}
// C++11 and later only...
_vector<T>& operator=(_vector<T> &&rhs) {
_vector<T> tmp(std::move(rhs));
std::swap(tmp.vc, vc);
std::swap(tmp._size, _size);
std::swap(tmp._capacity, _capacity);
return *this;
}
};

C++ Undefined reference to List<int>::GetCount() const [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
I am writing a simple data structure library, while I met some problems.
I wrote three files. collections.h is the header file, collections.cpp is to implement the methods declared in header file, main.cpp is for test. But compile error occurs:
Undefined reference to List::GetCount() const;
Undefined reference to List::IsEmpty() const;
Undefined reference to List::Add(int);
...// And so on.
I provide my code below, where is the problem?
collections.h:
#ifndef COLLECTIONS_H
#define COLLECTIONS_H
#include <windows.h>
#include <stdexcept>
template<typename T>
class ISequenceList
{
protected:
ISequenceList() { }
public:
virtual int GetCount() const = 0;
virtual bool IsEmpty() const = 0;
virtual void Add(T item) = 0;
virtual void AddRange(const T *items, int length) = 0;
virtual T &ElementAt(int index);
virtual bool InsertAt(T item, int index);
virtual bool Remove(T item) = 0;
virtual bool RemoveAt(int index) = 0;
virtual bool Contains(T item) = 0;
};
template<typename T>
class List : public ISequenceList<T>
{
private:
int _count;
int _capacity;
T *_array;
void ExpandCapacity();
public:
List(int capacity = 100)
{
if (capacity <= 0)
std::__throw_invalid_argument("The capcity can't be 0 or below.");
this->_count = 0;
this->_capacity = capacity;
this->_array = (T*)malloc(_capacity* sizeof(T));
}
List(const List &other)
{
if (this == other)
return;
this->_count = other->_count;
this->_capacity = other->_capacity;
free(_array);
this->_array = other->_array;
}
List &operator=(const List &other)
{
this = other;
}
~List()
{
if (_array)
free(_array);
}
int GetCount() const;
bool IsEmpty() const;
T &ElementAt(int index);
void Add(T item);
void AddRange(const T *items, int length);
bool InsertAt(T item, int index);
bool Remove(T item);
bool RemoveAt(int index);
bool Contains(T item);
};
#endif
collections.cpp:
#include "collections.h"
template<typename T>
void List<T>::ExpandCapacity()
{
T *temp = this->_array;
this->_array = (T*)malloc((this->_capacity << 1) * sizeof(T));
memcpy(this->_array, temp, this->_capacity * sizeof(T));
this->_capacity = this->_capacity << 1;
free(temp);
}
template<typename T>
int List<T>::GetCount() const
{
return this->_count;
}
template<typename T>
bool List<T>::IsEmpty() const
{
return this->_count == 0;
}
template<typename T>
void List<T>::Add(T item)
{
this->_array[_count] = item;
_count++;
if (_count == _capacity)
this->ExpandCapacity();
}
template<typename T>
void List<T>::AddRange(const T *items, int length)
{
if (length <= 0)
std::__throw_invalid_argument("The length can't be 0 or below.");
if (!items)
std::__throw_invalid_argument("The items can't be null");
int totalLength = this->_count + length;
if (totalLength >= this->_capacity)
{
T *temp = this->_array;
this->_array = (T*)malloc((totalLength << 1) * sizeof(T));
memcpy(_array, temp, this->_capacity);
free(temp);
}
this->_array += this->_capacity;
memcpy(_array, items, length * sizeof(T));
this->_capacity = totalLength << 1;
this->_count += length;
}
template<typename T>
T &List<T>::ElementAt(int index)
{
if (index < 0 || index >= _count )
std::__throw_invalid_argument("The index is out of bound.");
return _array[index];
}
template<typename T>
bool List<T>::InsertAt(T item, int index)
{
if (index < 0 || index > _count)
return false;
if (index == _count)
{
this->Add(item);
return true;
}
for (int i = _count; i > index; i--)
{
_array[i] = _array[i - 1];
}
_array[index] = item;
_count++;
if (_count == _capacity)
this->ExpandCapacity();
return true;
}
template<typename T>
bool List<T>::Remove(T item)
{
for (int i = 0; i < _count; i++)
{
if (_array[i] == item)
{
for (int j = i; j < _count; j++)
{
_array[j] = _array[j + 1];
}
_count--;
return true;
}
}
return false;
}
template<typename T>
bool List<T>::RemoveAt(int index)
{
if (index < 0 || index >= _count)
return false;
for (int j = index; j < _count; j++)
{
_array[j] = _array[j + 1];
}
_count--;
return true;
}
template<typename T>
bool List<T>::Contains(T item)
{
for (int i = 0; i < _count; i++)
{
if (_array[i] == item)
return true;
}
return false;
}
main.cpp:
#include "collections.h"
#include <iostream>
int main()
{
List<int> *seqList = new List<int>();
seqList->Add(5);
int arr[100] = {0};
seqList->AddRange(arr, 50);
seqList->ElementAt(5) = 111;
seqList->InsertAt(100, 15);
seqList->Remove(50);
seqList->ElementAt(44) = 44;
seqList->RemoveAt(44);
if (seqList->Contains(111))
std::cout << "Yes" << std::endl;
for (int i = 0; i < seqList->GetCount(); i++)
{
std::cout << seqList->ElementAt(i) << "\t";
}
return 0;
}
I have defined all the methods in List, but why can't the complier recognize? Where is the problem? Thanks for anyone who help me..
Note: my ide is Code::Blocks
Implementation of the template functions must be in a header; it can't be in a separate source file. The compiler needs to see it at the point where the template is used and its arguments become known.