Classes, dynamic arrays, constructors, and overloading

Okay here is what I'm tasked with:

Imagining vectors were not defined in C++ ...

Define a class called VectorDouble that is like a class for a vector with base type double. Your class VectorDouble will have a private member variable for a dynamic array of doubles. It will also have two member variables of type int, one called max_count for the size of the dynamic array of doubles; and one called count for the number of array positions currently holding values. (max_count is the same as the capacity of a vector; count is the same as the size of a vector)

If you attempt to add an element (a value of type double) to the vector object of the class VectorDouble and there is no more room, then a new dynamic array with twice the capacity of the old dynamic array is created and the values of the old dynamic array are copied to the new dynamic array.


Your class should have all of the following:

Three constructors: a default constructor that creates a dynamic array for 50 elements, a constructor with one int argument for the number of elements in the initial dynamic array, and a copy constructor.
A destructor.
A suitable overloading of the assignment operator =.
A suitable overloading of the equality operator ==. To be equal, the values of count and the count array elements must be equal, but the values of max_count need not be equal.
Member functions push_back, capacity, size, reserve, and resize that behave the same as the member functions of the same names for vectors.


Here is my futile attempt at it (80% complete I hope):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//Class declaration of VectorDouble
//VectorDouble.h

#ifndef VECTORDOUBLE_H
#define VECTORDOUBLE_H

#include <iostream>

using namespace std;

// VectorDouble class header file
class VectorDouble
{
    public://public member functions
    // default constructor
        VectorDouble();
    // constructor that take an int argument for an integer size of an array
        VectorDouble(int initial_size);
    // copy constructor
        VectorDouble(const VectorDouble &v);

    // destructor to return dynamic memory to the freestore
        ~VectorDouble();
    // overloaded operator = for VectorDouble class
        void operator =(const VectorDouble& v1);
    // overloaded operator == for VectorDouble class
        friend bool operator ==(const VectorDouble& v1,
                                 const VectorDouble& v2);
		//operations of vector class
    // adds a new element at the end of the array
        void push_back(double val);
    // returns allocated size of VectorDouble dynamic array
        int capacity() const;
    // returns the number of elements in VectorDouble
        int size() const;
    // allocates a specified block of memory for specified number of double
    // type values
        void reserve(int new_reserve);
    // changes the size of the dynamic array
        void resize(int new_size);
    // overload << operator
		friend ostream& operator <<(ostream& outs, const VectorDouble& v);

    private:

        void expandCapacity();
		//dynamic array pointer of type double
		double *elements;
        int maxCount; // the size of the array
        int count; // the number of elements stored
        
};

#endif VECTORDOUBLE_H

// end of the class declaration 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Implementation of the class VectorDouble.h header file

#include <iostream>
#include "VectorDouble.h"

using namespace std;

// Default constructor to create dynamic array of capacity maxCount

VectorDouble::VectorDouble() : maxCount(50)
{
    //create a dynamic arary of 50 elements
	elements = new double[maxCount];
    // number of elements are zero
    count = 0;
}

// constructor accepts an integer value sets the capacity of the vector
VectorDouble::VectorDouble (int size)
{
	//create dynamic array of size
	maxCount = size;
	elements = new double[maxCount];
	// number of elements are zero
	count =  0;
}

// Destructor to delete memnory

VectorDouble::~VectorDouble()
{
	// delete the pointer array
	delete [] elements;
}

// Overloading assignment (=) operator that copies the element
// Assigns a value to a VectorDouble object using the '=' operator.
	/*void VectorDouble::operator =(const VectorDouble& v1)
	{
		
	}*/

// Overloading equal to (==) operator and returns true if 
// 2 VectorDouble objects are equal otherwise return false.
// Checks to see if the values of two VectorDouble objects are the same.
	bool operator ==(const VectorDouble& v1, const VectorDouble& v2)
	{
		return (v1.elements == v2.elements);
	}

// Insert element into the dynamic array
void VectorDouble::push_back(double val)
{
	// if count is maximum size then expand
	 // the dynamic array by double
	if (count == maxCount)
		expandCapacity();

	elements[count] = val;
	count++;
}

// Method to return the maximum number of elements in the vector
int VectorDouble::capacity() const 
{ 
	// returns the size of the array
	return maxCount; 
}

// Method to return number of elements in array
int VectorDouble::size() const 
{ 
	// returns the number of elements in the array
	return count; 
}

// Method to allocate memory to the dynamic array with the specified size
void VectorDouble::reserve(int size)
{
	maxCount = size;
	double *newElements = new double[maxCount];
	// copy elements to newElements
	for (int i = 0; i < count; i++)
		newElements[i] = elements[i];

	// delete the space allocated to elements
	delete [] elements;

	elements = newElements; // point elements to newElements
}

// Overload the << operator to print the elements in the vector
ostream& operator <<(ostream& outs, const VectorDouble& v)
{
	for(int i = 0; i < v.count; i++)
		outs << v.elements[i] << endl;
	return outs;
}
 
// Method to expand the dynamic array size by double
void VectorDouble::expandCapacity()
{
	maxCount = 2 * maxCount;
	double *newElements = new double[maxCount];

	// copy elements to newElements
	for (int i = 0; i < count; i++)
		newElements[i] = elements[i];

	// delete the old memory
	delete [] elements;

	// point elements to newElements
	elements = newElements;
}



	

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*****************************************************
 * This	cpp program creates objects of class         *
 * VectorDouble and test the methods of class        *
 * VectorDouble and display the results of methods   *
 * and operators                                     *
 ****************************************************/

#include <iostream>
#include <conio.h>
#include "VectorDouble.h"

using namespace std;

int main()
{
	//create VectorDouble
	VectorDouble vector(5);

	// insert double values into the vector object
	vector.push_back(12.5);
	vector.push_back(13.5);
	vector.push_back(14.5);
	vector.push_back(15.5);
	vector.push_back(16.5);

	//display size and capacity of the vector
	cout << "VectorDouble vector " << endl;
	cout << "Capacity of the VectorDouble: "<< vector.capacity() << endl;
	cout << "Size of the VectorDouble: "<< vector.size() << endl;

	// Display example of resize
	cout << "insert element in to the vector "<< endl;
	vector.push_back(17.5);
	cout << "Size of VectorDouble after resize method calling: "<< vector.size() << endl;

	cout << "/nVectorDouble temp "<< endl;
	cout << "Copy Constructor" << endl;

	// Create other vector temp of size 5
	VectorDouble temp(5);
	temp.push_back(18.5);
	temp.push_back(19.5);
	temp.push_back(20.5);

	// Use copy constructor
	VectorDouble copyConstructor(temp);
	cout << copyConstructor;
	cout << "equality operator (==) checking on vector == temp "<< endl;

	// Assign temp object to vectorobject using assignment operator
	vector = temp;
	cout << vector;

	cout <<"/nChecking resize() function" << endl;
	// call resize mehtod
	vector.resize(3);

	cout << "size of the new vector" <<vector.capacity() << endl;
	cout << vector;

	cout << "Checking reserve() function" << endl;
	// call reserve function
	vector.reserve(40);
	cout <<"Reserve new memory using reserve function" << endl;
	cout << "Size of new vector" << vector.capacity() << endl;
	cout << vector;

	getch();
	return 0;
}// end of main method 

If I can get my code polished up, I promise I will never ask another question (unfortunately discovering my lack of passion for coding :[ )

1>------ Build started: Project: Final_Project, Configuration: Debug Win32 ------
1>Interface_VectorDouble.obj : error LNK2019: unresolved external symbol "public: void __thiscall VectorDouble::resize(int)" (?resize@VectorDouble@@QAEXH@Z) referenced in function _main
1>Interface_VectorDouble.obj : error LNK2019: unresolved external symbol "public: void __thiscall VectorDouble::operator=(class VectorDouble const &)" (??4VectorDouble@@QAEXABV0@@Z) referenced in function _main
1>Interface_VectorDouble.obj : error LNK2019: unresolved external symbol "public: __thiscall VectorDouble::VectorDouble(class VectorDouble const &)" (??0VectorDouble@@QAE@ABV0@@Z) referenced in function _main
1>C:\Users\: fatal error LNK1120: 3 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Pretty cryptic error messages there.

Here's what I get:
1
2
3
4
5
6
$ clang++ main.cpp vectordouble.cpp 
/tmp/main-gRHy95.o: In function `main':
main.cpp:(.text+0x30c): undefined reference to `VectorDouble::VectorDouble(VectorDouble const&)'
main.cpp:(.text+0x370): undefined reference to `VectorDouble::operator=(VectorDouble const&)'
main.cpp:(.text+0x3d5): undefined reference to `VectorDouble::resize(int)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)


What the above means is that you have declared those functions but not defined them.
Pretty cryptic error messages there


Not really. They're nearly identical to the ones you posted apart from some extra name mangling.
I didn't intend for the error messages to divert from the fact that the coding is incomplete and needs work.
I thought that perhaps it could help focus in on particular areas that needs completing.
I'm a tad ashamed and desperate at this point.
norm b already explained the problem.

There are 3 functions:

- VectorDouble::VectorDouble(VectorDouble const&)
- VectorDouble::operator=(VectorDouble const&)
- VectorDouble::resize(int)


These functions are being called by your code, but they do not have a body.

You need to give them a body.
I need help completing the incomplete parts of my code such as the ones you specified ... I'm trying to work at this at the same time ... here's my failed attempt:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void VectorDouble::operator =(const VectorDouble& v, double val)
		{
			int size = v.size();
			count = size;
        
			if(size > maxCount)
			{
					delete [] val;
					maxCount = size;
					val = new double[maxCount];
			}
                for (int i=0; i<size; i++)
                val[i]=v.val[i]
		
		}


In case it's not obvious, I know a little, but not a lot, and at this point I'm begging for answers as I've come so far and to be honest, I'm getting burnt out.
Last edited on
See comments below (untested):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void VectorDouble::operator =(const VectorDouble& v1) 
	    // The signature in your header file is correct. Changed v to v1
{
    int size = v1.size();
    count = size;
     
    if(size > maxCount) // Are vectors equal if the maximum size is different 
			// i.e. the vector being copied is smaller?
    {
      delete [] val;		// the member elements points to the array
      maxCount = size;
      val = new double[maxCount];  // again use elements
    }
    for (int i=0; i<size; i++)
      val[i]=v1.val[i]   // this should be    elements[i] = v1.elements[i] 
}
Thanks!
It's telling me that VectorDouble has no member 'val' and that it's undefined, even though I have it in the push_back function
The variable val in push_back() is local to that function. It is created when the function is called and is destroyed when the function block terminates.

You don't need a val variable in operator =(). Perhaps putting the implied this pointer (http://www.learncpp.com/cpp-tutorial/87-the-hidden-this-pointer/) in the code will help:

1
2
3
4
5
6
7
8
9
10
void VectorDouble::operator =(const VectorDouble& v1){    
    if(this->maxCount != v1.maxCount){
        delete [] this->elements;  // delete the old array
        this->maxCount = v1.maxCount;
        this->elements =  new double[this->maxCount];  // create new array the size of v1
    }
    this->count = v1.size();
    for(int i =0; i< count;++i)	// copy v1 into the new array
        this->elements[i] = v1.elements[i];
}

You are passing v1 into the function and when it returns the current object (this) will be a copy of v1.

You can remove "this->" from your code.
closed account (N36fSL3A)
Wouldn't it be easier to use a class template?

I'm not an expert on them, but I heard templates can take any value.

Just read the topic again.

Anyway, if I was asked that question, I'd personally do something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class VectorDouble
{
    public:
        void push_back(double val)
        {
            length++;
            double* tmp = value;
            
            delete value[];
            value = new double[length];
            for(unsigned len = 0;len < length; len++)
            {
                *value = tmp[len];

                ++value;
            }

            delete tmp[];
        }

        unsigned int size() const{return length;}

    private:
        unsigned int length;

        double* value;
};
Last edited on by Fredbill30
Templates may be easier but that's a concept that I can't utilize.
Here's what I'm tasked with:

Imagining vectors were not defined in C++ ...

Define a class called VectorDouble that is like a class for a vector with base type double. Your class VectorDouble will have a private member variable for a dynamic array of doubles. It will also have two member variables of type int, one called max_count for the size of the dynamic array of doubles; and one called count for the number of array positions currently holding values. (max_count is the same as the capacity of a vector; count is the same as the size of a vector)

If you attempt to add an element (a value of type double) to the vector object of the class VectorDouble and there is no more room, then a new dynamic array with twice the capacity of the old dynamic array is created and the values of the old dynamic array are copied to the new dynamic array.


Your class should have all of the following:

Three constructors: a default constructor that creates a dynamic array for 50 elements, a constructor with one int argument for the number of elements in the initial dynamic array, and a copy constructor.
A destructor.
A suitable overloading of the assignment operator =.
A suitable overloading of the equality operator ==. To be equal, the values of count and the count array elements must be equal, but the values of max_count need not be equal.
Member functions push_back, capacity, size, reserve, and resize that behave the same as the member functions of the same names for vectors.


Here is where I'm coming up short:

There are 3 functions:

- VectorDouble::VectorDouble(VectorDouble const&)
- VectorDouble::operator=(VectorDouble const&) *might be resolved*
- VectorDouble::resize(int)


These functions are being called by my code, but they do not have a body.
closed account (N36fSL3A)
I wrote:
Wouldn't it be easier to use a class template?

I'm not an expert on them, but I heard templates can take any value.

Just read the topic again.
Just putting that out there.

resizing should be fairly easy. I' guessing I'd edit the push_back() thing above to check if the pointer is large enough, for resizing just do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void resize(unsigned int val)
{
    double* tmp = value; 
    
    delete value[];

    value = new double[val];

    for(unsigned int len = 0; len < length; len++)
    {
        *value = tmp[len];

        ++value;
    }
}


Very, very simple.

EDIT - actually, you should use an unsigned int as it doesn't make sense to resize the vector to a negative value... (You know what, this makes me want to take on this challenge)
Last edited on by Fredbill30
Very, very simple.


Then it's a shame you couldn't supply code that would compile or do something that didn't result in undefined behavior.
closed account (N36fSL3A)
I actually made a simple class, then realized this code sucked.

Something like this. I'm actually debugging it right now, so it will probs result in undefined behavior.

Not exactly the fastest way. I did however test all the functions, and they worked fine when I did.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <iostream>

#ifndef _DYNARRAY_H_
#define _DYNARRAY_H_

class VectorDouble
{
	public:
		VectorDouble()
		{
			value  = new double[0];
			length = 0;
			cap = 0;
		}
	
		void push_back(double val)
		{
			int arrsize  = 8 * cap;
			
			int arrsize2 = 8 * (length + 1);
		
			if((arrsize) <= (arrsize2))
			{	
				double* tmp = value;
				
				/*for(unsigned int len = 0; len < length; len++)
				{
					value[len] = tmp[len];
				}*/
				value[length] = val;
				
				length++;
				if((arrsize) == (arrsize2))
				{
					resize(length + 1);
				}
				
				delete[] tmp;
			}
			
			else
			{
				resize(arrsize2);
				push_back(val);
			}
		}
		
		void pop_back()
		{
			if(length > 0)
			{
				length--;
				double* tmp = value;
				
				delete[] value;
				value = new double[length];
				
				for(unsigned int len = 0; len < length; len++)
				{
					value[len] = tmp[len];
				}
				
				delete[] tmp;
			}
			
			else
			{
				std::cout << "Vector is already equal to zero\n";
			}
		}
		
		unsigned int size()
		{
			return length;
		}
		
		unsigned int capacity()
		{
			return capacity();
		}
		
		void reserve(unsigned int amount)
		{
			delete[] value;
			value = new double[amount];
		}
		
		void resize(unsigned int amount)
		{
			double* tmp = value;
		
			delete[] value;
			value = new double[amount];
			
			cap = amount;
			
			for(unsigned int v = 0; v < cap; v++)
			{
				value[v] = tmp[v];
			}
			delete[] tmp;
		}
		
		// The [] operator
		double &operator[](unsigned int index)
		{
			if(index > length)
			{
				std::cout << "Vector index out of range\n";
			}
			
			else
			{
				return value[index];
			}
		}
		
		~VectorDouble()
		{
			delete[] value;
		}
	
	private:
		double* value;
		
		unsigned int length; // The length of the variable
		unsigned int cap;
};

#endif//_DYNARRAY_H_ 


EDIT - Compiled with MinGW btw.
Last edited on by Fredbill30
Not exactly the fastest way. I did however test all the functions, and they worked fine when I did.

Compiling is not testing. For instance, testing this member function:
1
2
3
4
		unsigned int capacity()
		{
			return capacity();
		}
would immediately reveal that something was wrong.

You managed to get the destructor, the default constructor, operator[] and size correct. Everything else is wrong and would result in very odd behavior if you did actually exercise the class.

Don't say you've tested stuff you haven't tested. It's irksome.
closed account (N36fSL3A)
Yea, never tested that function. That's fixed, however in my most recent build.
Topic archived. No new replies allowed.