|
 |
|
 |
01-27-2005, 09:02 AM
|
#1 (permalink)
|
|
mike
Join Date: Jan 2005
Location: Ottawa, ON
Posts: 79
|
I need some practice Idea's
I want to start a medium-sized project for myself (about 3-600 lines would do, maybe much more or less depending on the idea) or maybe a few smaller ones would be better. I've been thinking of a few ideas but I would like some more suggestions. Here's some things I want to learn/practice:
- Basic File I/O
- Basic Computer Science (fibonacci, towers of hanoi, etc..)
- Vegas Games (poker, blackjack)
- Simple Data Structures (linked lists, an array class)
I would probably like to do either the poker game (and maybe reading/storing results to a file, possibly encrypted) or the towers of hanoi. If I was to do either of those I would need a website showing the rules for either one.
I would really like some suggestions on what to do with any of these project ideas though, like a useful application of a linked list for example or something cool to do with basic file i/o.
Thanks.
|
|
|
01-27-2005, 12:54 PM
|
#2 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
Do the array class. Much to learn with that.
Use this as your starter:
Code:
template<typename T>
class CArray
{
public:
CArray();
CArray(unsigned, unsigned = 0); //size, base
~CArray();
CArray(const CArray& );
CArray& operator=( const CArray&);
protected:
T* _data;
unsigned _base;
unsigned _length;
};
Define the following to start with:
- constructor
- copy constructor
- operator=
- destructor
Then we move on.
__________________
|
|
|
01-27-2005, 01:45 PM
|
#3 (permalink)
|
|
mike
Join Date: Jan 2005
Location: Ottawa, ON
Posts: 79
|
I'm trying that right now, thanks. Can you explain your class member for me? Thanks.
|
|
|
01-27-2005, 01:52 PM
|
#4 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
By default, arrays start with index "0". So...
Code:
CArray<int> theArray(6);
... the first index will start at "theArray[0]", and has a size of 6 elements.
However...
Code:
CArray<int> theArray(6, 1);
... still has the size of 6, but the first element starts at index 1.
Furthermore, I am asking you to implement the copy constructor, assignment operator and destructor first for a reason. Do you know what is so special about them? That's the whole point of this excercise.
If you do not know why, then don't implement them yet. Implement only the two constructors I gave you, and the destructor.
__________________
|
|
|
01-27-2005, 02:13 PM
|
#5 (permalink)
|
|
mike
Join Date: Jan 2005
Location: Ottawa, ON
Posts: 79
|
Quote:
|
Originally Posted by Valmont
Furthermore, I am asking you to implement the copy constructor, assignment operator and destructor first for a reason. Do you know what is so special about them? That's the whole point of this excercise.
|
I understand the assignment operator and the destructor well, I'm a little shaky on the copy constructor.
The overloaded assignment operator would copy the elements of the CArray argument to _data of the current object (this), something like this:
Code:
for(int i = 0; i < _length; i++)
_data[i] = argumentArray._data[i];
The destructor is required to free up the memory block allocated in the constructor calls. I'm reading a bit about operator overloading, and copy constructors next. In about an hour or two I'll show you what I've got done so far, but I can't work too late tonite on this because I have an m68000 lab due tomorrow I haven't finished.
I imagine the copy constructor is required when doing an assignment in main like this:
Code:
CArray x, y(7);
// ... fill y with some values
x = y;
I'm a little rusty on copy constructors, templates and operator overloading, I'm reading up on them now.
|
|
|
01-27-2005, 02:40 PM
|
#6 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
Take your time. You ddin't answer my questions. You explained what they are more or less but not why they are so special. Forget about the assignment operator and copy constructor. Implement the rest first. We are going to demonstrate what's going on without them.
See ya perhaps tomorrow. Good luck!
__________________
|
|
|
01-27-2005, 04:25 PM
|
#7 (permalink)
|
|
mike
Join Date: Jan 2005
Location: Ottawa, ON
Posts: 79
|
I'm having trouble with some stuff, I'm going to start this with no templates (just use int's for now) and no extended indexing capabilities. This is pretty tough for me...
|
|
|
01-27-2005, 04:39 PM
|
#8 (permalink)
|
|
mike
Join Date: Jan 2005
Location: Ottawa, ON
Posts: 79
|
Edit: OK I did what you asked for originally, I'm better at doing things then explaining them. I'd be really interested to hear what you think and where to go next with this project, and I'll keep updating as I do. I think I'll be taking the next 2-3 days off it because of school, but I might be able to sneak in some time to work on it tomorrow and over the weekend. I'm pretty much done C++ for tonite, I have homework to start now. Thanks for motivating me off my butt to do some code
ArrayClass.h
Code:
class CArray
{
public:
CArray();
CArray(unsigned arraySize);
~CArray();
// copy constructor
CArray(const CArray &arrayToCopy);
// overloaded assignment operator
CArray& operator=(CArray &arrayToCopy);
protected:
int *_data;
unsigned _length;
};
ArrayClass.cpp
Code:
#include <iostream>
#include <new>
#include "ArrayClass.h"
using namespace std;
// default constructor
CArray::CArray()
{
// nothing was passed so assume
// an array of 10 elements
_length = 10;
_data = new int[_length];
// and initialize values to 0
for(int i = 0; i < _length; i++)
_data[i] = 0;
}
// overloaded constructor
CArray::CArray(unsigned arraySize)
{
// make sure no size of 0
if(arraySize == 0)
_length = 10;
else
_length = arraySize;
_data = new int[_length];
// initialize values to 0
for(int i = 0; i < _length; i++)
_data[i] = 0;
}
// destructor
CArray::~CArray()
{
delete [] _data;
}
// copy constructor
CArray::CArray(const CArray & arrayToCopy)
{
_length = arrayToCopy._length;
_data = new int[_length];
for(int i = 0; i < _length; i++)
_data[i] = arrayToCopy._data[i];
}
// overloaded assignment operator
CArray& CArray::operator=(CArray & arrayToCopy)
{
// check length of arrayToCopy
if(arrayToCopy._length > _length)
{
delete [] _data;
_length = arrayToCopy._length;
_data = new int[_length];
}
// copy elements from arrayToCopy into _data
for(int i = 0; i < _length; i++)
_data[i] = arrayToCopy._data[i];
return *this;
}
main.cpp
Code:
#include <iostream>
#include "ArrayClass.h"
int main(void)
{
CArray arr1;
CArray arr2(6);
CArray arr3(arr2);
arr2 = arr1;
return 0;
}
BTW: How do you post C++ code with syntax highlighting like you do? It makes it much easier to read... 
Last edited by fp_unit; 01-27-2005 at 05:18 PM.
|
|
|
01-27-2005, 10:52 PM
|
#9 (permalink)
|
|
Newbie
Join Date: Jun 2002
Location: Denmark
Posts: 1,720
|
Quote:
|
BTW: How do you post C++ code with syntax highlighting like you do? It makes it much easier to read...
|
You make your own program, which will read the *.cxx/*.hxx files and based uppon a number of keywords and such it will replace those with the equivalent [color ]keyword[/ color] tag showing them in the right color, like your editor would do, then you paste what ever contence produced into your [code ][/ code] tags here.
|
|
|
01-27-2005, 10:58 PM
|
#10 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
Quote:
|
Originally Posted by redhead
You make your own program, which will read the *.cxx/*.hxx files and based uppon a number of keywords and such it will replace those with the equivalent [color ]keyword[/ color] tag showing them in the right color, like your editor would do, then you paste what ever contence produced into your [code ][/ code] tags here.
|
I think you can download them as well, otherwise there are online syntax highlighters as well. Mine is just a console programa accepting .h and .cpp files and then parsing through them. It is buggy yet. I need to do some online editing sometimes but I have no time (or will) to look at it.
__________________
|
|
|
01-28-2005, 01:24 AM
|
#11 (permalink)
|
|
Moderator
Join Date: May 2002
Location: us.ca
Posts: 4,505
|
this is a great point. i would really like to implement a c++ highlighter for codenewbie. are there any c++ to html highlighting converters?
__________________
Mike
|
|
|
01-28-2005, 01:32 AM
|
#12 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
Tons of them. I never know what to do with them so I don't have em.
__________________
|
|
|
01-28-2005, 02:10 AM
|
#13 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
First of all we want a generic class array. I'll help you on your way. But let's first analyze what you got so far.
Quote:
Code:
// default constructor
CArray::CArray()
{
// nothing was passed so assume
// an array of 10 elements
_length = 10;
_data = new int[_length];
// and initialize values to 0
for(int i = 0; i < _length; i++)
_data[i] = 0;
}
|
- Why do you assume things?
Right now you are a library writer. That is a hard job. Intellectually, but other responsibilites are present as well: how much freedom will you give the client coder (the person who uses your library)? Shouldn't he decide for himself what the size of the array is?
Solution: build a "resize" or "set_size" method.
- Why do you initialize the array to 0's? Did you read something in a book about initializing arrays to zero's because it avoids certain anomalies?
What (when we have a generic array) will you initialize it with then? You can't assume that zero's are always a valid input!
- Why do you call it a "default" constructor?
It is not a default constructor at all. It is the overloaded default constructor with no parameters!
Quote:
Code:
// overloaded constructor
CArray::CArray(unsigned arraySize)
{
// make sure no size of 0
if(arraySize == 0)
_length = 10;
else
_length = arraySize;
_data = new int[_length];
// initialize values to 0
for(int i = 0; i < _length; i++)
_data[i] = 0;
}
|
- Why do you create a new array?
All it ask for is the size of an upcoming array. Don't do more then what I, as a client coder, expect.
- Also here, we are not interested in initializing the array with zero's or any value at all.
- Why do you call it an "overloaded" constructor.
It is not. It is a constructor that takes one parameter. A constructor that takes one parameter is also called an implicit conversion operator.
Quote:
Code:
CArray::CArray(const CArray & arrayToCopy)
{
_length = arrayToCopy._length;
_data = new int[_length];
for(int i = 0; i < _length; i++)
_data[i] = arrayToCopy._data[i];
}
|
- You can optimize this code by using a proper constructor. See later for my version.
Quote:
Code:
// overloaded assignment operator
CArray& CArray::operator=(CArray & arrayToCopy)
{
// check length of arrayToCopy
if(arrayToCopy._length > _length)
{
delete [] _data;
_length = arrayToCopy._length;
_data = new int[_length];
}
// copy elements from arrayToCopy into _data
for(int i = 0; i < _length; i++)
_data[i] = arrayToCopy._data[i];
return *this;
}
|
- Why don't we need to check for self-assignment in this case?
- Why should we do it now anyway?
- What's up with self-assignment and overloading the asssignment operator?
- Why do we return *this?
- Why not return "this", without the star?
- Why do we return by reference?
OK. Here is my code so far. Then I will give you new tasks and ask a few questions:
Code:
#ifndef CARRAY_H
#define CARRAY_H
#include <stdexcept>
template<typename T>
class CArray
{
public:
CArray();
CArray(unsigned, unsigned = 0); //size, base
virtual ~CArray();
CArray(const CArray&);
unsigned get_base() const;
unsigned get_length() const;
void set_base(unsigned);
void set_length(unsigned);
CArray& operator=(const CArray&);
protected:
T* _data;
unsigned _base;
unsigned _length;
};
//------------------------------------------------------
// The mandatory stuff.
template<typename T>
CArray<T>::CArray() : _data(new T[0]), _base(0), _length(0)
{}
//------------------------------------------------------
template<typename T>
CArray<T>::CArray(unsigned n, unsigned m) :
_data(new T[n]), _base(m), _length(n)
{}
//------------------------------------------------------
template<typename T>
CArray<T>& CArray<T>::operator=(const CArray& rhs)
{
if(&rhs != this)
{
if(rhs._length > _length)
{
delete[] _data;
_length = rhs._length;
_data = new T[_length];
}
for(unsigned i = 0; i < _length; ++i)
{
_data[i]=rhs._data[i];
}
_base = rhs._base;
}
return *this;
}
//------------------------------------------------------
template<typename T>
CArray<T>::CArray(const CArray& other) :
_data(new T[other._length]), _base(other._base), _length(other._length)
{
for(unsigned i = 0; i < _length; ++i)
{
_data[i]=other._data[i];
}
}
//------------------------------------------------------
template<typename T>
CArray<T>::~CArray()
{
delete[] _data;
}
//
//------------------------------------------------------
#endif //CARRAY_H
tasks
- Study my class.
- Implement the new things you see in the class declaration.
- Then I want you to implement (overload) operator[] for my class. This is a tricky one. The code is very simple. But there is a caveat. See how far you can get.
questions
- Why is my destructor virtual?
- Once again, what is so special about the combination: destructor+ copy_ctor + operator= ?
- Prove in your main() that you can handle my class as a client programmer.
a) Initialize an array with 3 elements of type std::string.
b) Assign the elements these values: "a", "b" and "c".
c) Initialize another std::string array (caveat!).
d) Assign OR initialize this new array with the previous one.
e-1) Forward the three elements of the new array to the (bash/console) screen.
e_2) We'll do that later together.
Take your time. Do bit by bit and post code. Feel free to ask questions. You're here to learn. Everything in this assignment has a plan.
__________________
|
|
|
01-28-2005, 03:09 PM
|
#14 (permalink)
|
|
mike
Join Date: Jan 2005
Location: Ottawa, ON
Posts: 79
|
Quote:
|
Originally Posted by Valmont
- You can optimize this code by using a proper constructor. See later for my version.
|
I understand how your constructors are assigning values - I didn't know you could do that in C++ until reading some of your code last night. Could you explain the "effiency" behind it? I assume it has to do with bypassing the creation of a tempory object, but correct me if I'm way off.
Quote:
|
Originally Posted by Valmont
Why don't we need to check for self-assignment in this case?
|
Why don't we? I didn't really think of self-assignment when writing that overloaded assignment operator. I would actually think you *would* need it.
Quote:
|
Originally Posted by Valmont
Why should we do it now anyway?
|
It's a waste of time copying every element of array_m to array_n when they are in fact have the same values. I imagine this could further be optimized as well to copy a CArray that has say, the first 50 elements being the same, with possibly the last 20 elements being different.
Quote:
|
Originally Posted by Valmont
What's up with self-assignment and overloading the asssignment operator?
|
As I said above, I think its pointless to copy element-by-element, values from array_m to array_n if they are the same. On to overloading the assignment operator, we want to be able to assign entire CArrays to each other, as in array_m = array_n; or array_m = array_n - array_o;
Quote:
|
Originally Posted by Valmont
Why do we return *this?
|
Well since we're creating a new object with the same values, looping through and copying element-by-element would be useless. Since this is a pointer to the current object, we're basically saying (in int main()):
new_object_address = old_object_address;
I'm not exactly sure of the complete internal details yet, I've learned much in the past 24 hours. I'm still relatively new to C++ and I'm still learning.
Quote:
|
Originally Posted by Valmont
Why not return "this", without the star?
|
To be honest, I tried that first and it wouldn't compile  No seriously, I just tried printing the values of *this and this, *this can't be printed (yet??). this prints the address. I remember doing more basic pointers with primitive data types like int, and *ptr held the value (dereferenced pointer) while ptr held the address. In this situation, since CArray is a data type, I think my old analogy above is wrong, and in main() we're actually saying:
new_object = old_object; // literally
I'm confusing myself just trying to think this all through! It is helping though, although I have to throw out some of my older "comfort assumptions" - why things worked without really knowing!
Quote:
|
Originally Posted by Valmont
Why do we return by reference?
|
Last one! Frankly my brain hurts and I can't really remember. Why, why... OK, here's the call statement:
string1 = string2;
So... operator= returns a reference (the address is returned to string1) to itself (self-assignment) or it's updated values (from string2). string2 must be passed to operator= by reference because we need to access it's members to perform the element-by-element copy, plus we may need it's length and base. I'm pretty sure we could have passed it by value, although that could be a large copy operation, although it seems safer...
We are forced to return by reference, because string1's address will change depending when operator= returns (unless self-assignment is performed - nothing will change in that case).
I really racked my brain trying to answer all of those, and they just don't 'sound' right. I don't think many are. Please correct me where I'm wrong. Anyways, on to the code: You left these exercises for me to try:
Quote:
|
Originally Posted by Valmont
tasks
- Study my class.
- Implement the new things you see in the class declaration.
- Then I want you to implement (overload) operator[] for my class. This is a tricky one. The code is very simple. But there is a caveat. See how far you can get.
questions
- Prove in your main() that you can handle my class as a client programmer.
a) Initialize an array with 3 elements of type std::string.
b) Assign the elements these values: "a", "b" and "c".
c) Initialize another std::string array (caveat!).
d) Assign OR initialize this new array with the previous one.
e-1) Forward the three elements of the new array to the (bash/console) screen.
e_2) We'll do that later together.
Take your time. Do bit by bit and post code. Feel free to ask questions. You're here to learn. Everything in this assignment has a plan.
|
You also left these 2 questions:
Quote:
|
Originally Posted by Valmont
- Why is my destructor virtual?
- Once again, what is so special about the combination: destructor+ copy_ctor + operator= ?
|
I really can't answer these one's yet, at least until I hear your response to the code I have now. I'll listen to your response first, anyways, on to the code:
CArray.h
Code:
#ifndef CARRAY_H_
#define CARRAY_H_
#include <stdexcept>
#include <new>
template<typename T>
class CArray
{
public:
CArray();
CArray(unsigned, unsigned = 0);
virtual ~CArray();
CArray(const CArray&);
unsigned get_base() const { return _base; }
unsigned get_length() const { return _length; }
void set_base(unsigned b) { _base = b; }
void set_length(unsigned l) { _length = l; }
void print() { cout << this << endl; };
// Should I be defining these
// overloaded operators outside the class?
CArray& operator= (CArray& arrayToCopy);
T& operator[](unsigned);
protected:
T* _data;
unsigned _base;
unsigned _length;
};
template<typename T>
CArray<T>::CArray() : _data(new T[0]), _base(0), _length(0)
{}
template<typename T>
CArray<T>::CArray(unsigned n, unsigned m) :
_data(new T[n]), _base(m), _length(n)
{}
template<typename T>
CArray<T>::~CArray()
{
delete [] _data;
}
// copy constructor
template<typename T>
CArray<T>::CArray(const CArray& other) :
_data(new T[other._length]), _base(other._base), _length(other._length)
{
for(unsigned i = 0; i < other._length; ++i)
_data[i] = other._data[i];
}
// overloaded assignment operator
template<typename T>
CArray<T>& CArray<T>::operator=(CArray & rhs)
{
if(&rhs != this)
{
if(rhs._length > _length)
{
delete [] _data;
_length = rhs._length;
_data = new T[_length];
}
for(int i = 0; i < _length; i++)
_data[i] = rhs._data[i];
_base = rhs._base;
}
return *this;
}
template<typename T>
T& CArray<T>::operator[](unsigned i)
{
// I'm trying not to assume anything, so I'm not performing
// any bounds checking - I dont know what to do for an
// "out-of-range" access attempt - exit? error message?
return _data[i]; // return data at element[i]
}
#endif
main.cpp
Code:
#include <iostream>
using namespace std;
#include "CArray.h"
int main(void)
{
CArray<string> cStr1(3);
cStr1[0] = "a";
cStr1[1] = "b";
cStr1[2] = "c";
cout << cStr1[0] << cStr1[1] << cStr1[2] << endl;
// Test the copy constructor
CArray<string> cStr2(cStr1);
cout << cStr2[0] << cStr2[1] << cStr2[2] << endl;
// Test overloaded assignment operator
cStr1 = cStr2;
cout << cStr1[0] << cStr1[1] << cStr1[2] << endl;
return 0;
}
Thanks for your help so far Valmont 
|
|
|
01-28-2005, 07:55 PM
|
#15 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
1) I will reply to your answer by posting a few pages of the improved tutorial on operator overloading. Better read these instead of the original. You will receive many answers.
2) You implemented the most important part: operator[].
However, I announced a caveat. Here it is:
What happens if you pass const objects to operator=() ?
How do you fix it?
On the next replies I will post the relevant pages. The moral of the story so far was:
For any class that holds members that dynamically allocate memory, implement these three items:
1) copy constructor
2) overloaded assignment operator
3) a destructor
This is called: The Rule Of Three.
- copy ctor
prevents double deletion errors.
- assignment operator
prevents double deletion errors and self destruction and memory leaks.
- destructor
cleanup obviously
The second moral is this:
When implementing operator[], consider implenting another version to deal with const objects. Try this one alone. After that, I will post my complete CArray class because you've worked hard enough.
You're answers were basically incomplete and inaccurate. However, the impression I've got is that you did real good. Good attempts. If this was an intermadiate test, I would have given you a score of 80% out of 100%. For the effort.
__________________
|
|
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
| | |