-
June 25th, 2009, 09:27 AM
#1
Templated class and iostream overloading
Well first I want to say hello to all the users here.
I'm a beginner in C++ and I'm trying to program a vector class for a Math Utility library I'm working on as my first big project written in C++... Well everything is working as expected but I have some questions.
-Info:
All my vector class is in a header file and using the namespace mut (it stands for Math Utility Toolkit, I might change the name but it's ok for the moment) and I'm using a template like this:
Code:
namespace mut{
template <class T=int> //Default vector storage is int
class vector{
.......
}
}
I wanted to add iostream operators to my class and this is what I did:
Code:
//IOSTREAM operators
template <class T>
ostream& operator<<(ostream& os, vector<T> &vec){
int i = 0;
os << "(";
for(i = 0; i < vec.length() - 1; i++){
os << vec[i] << ", ";
}
os << vec[i] << ")" << endl;
return os;
}
template <class T>
istream& operator>>(istream& is, vector<T> &vec){
int i = 0;
for(i = 0; i < vec.length(); i++){
is >> vec[i];
}
return is;
}
So my question is:
I used the template again since these operators are outside the class definition but I don't know if there is a better way or if this is ok...
And a second question is "is there a better way of formatting the output for my vector like so?": (vec[0], vec[1], vec[2]...)
I achieved this format but i don't know if the function can be optimised...
Well thanks in advance!
If you need more info, let me know
BB!
-
June 25th, 2009, 09:33 AM
#2
Re: Templated class and iostream overloading
Originally Posted by beta3designs
I used the template again since these operators are outside the class definition
Before you do anything else, please append the appropriate namespace onto "vector" in your code.
Code:
template <class T>
ostream& operator<<(ostream& os, mut::vector<T> &vec){
The reason is that there already is a "vector" class in C++. Leaving the term "vector" without a namespace could cause compiler errors if your code is included in any source module that uses std::vector.
As a matter of fact, all of those types should be prepended with their appropriate namespace (i.e. std::ostream, etc.). If you already have a "using namespace" clause before that code, get rid of it.
Edit: Why are you not using the existing std::vector class? Why do you need to create your own?
Regards,
Paul McKenzie
Last edited by Paul McKenzie; June 25th, 2009 at 09:40 AM.
-
June 25th, 2009, 09:43 AM
#3
Re: Templated class and iostream overloading
Before you do anything else, please append the appropriate namespace onto "vector" in your code.
Sorry, I forgot to say it was in namespace mut{} but outside class vector{}.
Ok thanks ill get rid of using namespace std...
And well it's just for the library... i like to program everything myself and since it is a math library i thought it would be good to have my own vector class...
Thanks for your help!
Still willing to know if there is a better way for what I did.
Thanks in advance!
BB!
-
June 25th, 2009, 09:58 AM
#4
Re: Templated class and iostream overloading
Originally Posted by beta3designs
i like to program everything myself and since it is a math library i thought it would be good to have my own vector class...
So is the goal to have a math library, or to maintain a vector class?
That is the question I always ask to someone who wants to write everything themselves. It's as if you're building a house, and instead of buying a hammer, you make your own hammer, instead of buying paint, you make your own paint, etc. While you're making your own hammer and making your own paint (and then have to test if your home made version works), another person is building the same house using store bought hammer and paint, and is almost finished by the time you've got your home-made hammer and paint solution finished.
Unless there is a compelling reason to write things yourself, you should always consider the standard containers, even if just to quickly prototype your code to see if it actually will work.
Still willing to know if there is a better way for what I did.
Code:
ostream& operator<<(ostream& os, vector<T> &vec){
The second parameters should be a const reference. You are not changing values, you are merely reading from the vector. If you get a compiler error if you make it a const reference, it is more than likely going to be this:
Code:
os << vec[i] << ", ";
Operator [] must have two versions, a const and non-const version. I don't know if you provided it, but I'm preparing you for what could cause a problem once you start passing const references to your vector class.
Otherwise, there is really no difference if the template function is inline or not inlined. The only thing you have to be aware of is that the non-lined version of the template function has to still "ride" with the template header, i.e., the code must be included at the end of the template declaration.
Regards,
Paul McKenzie
Last edited by Paul McKenzie; June 25th, 2009 at 10:08 AM.
-
June 25th, 2009, 11:29 AM
#5
Re: Templated class and iostream overloading
Originally Posted by Paul McKenzie
Edit: Why are you not using the existing std::vector class? Why do you need to create your own?
It sounds like beta3designs is writing a class to represents a mathematical vector (as in vector quantity, as opposed to scalar quantity), and not the kind of "vector" that std::vector is.
Now whether it makes sense to implement the mathematical vector class in terms of std::vector, is another question. (I'd argue yes, just be careful to avoid name clashes )
Old Unix programmers never die, they just mv to /dev/null
-
June 25th, 2009, 11:31 AM
#6
Re: Templated class and iostream overloading
Originally Posted by beta3designs
Code:
template <class T>
ostream& operator<<(ostream& os, vector<T> &vec){
int i = 0;
os << "(";
for(i = 0; i < vec.length() - 1; i++){
os << vec[i] << ", ";
}
os << vec[i] << ")" << endl;
return os;
}
What if the vector is empty (size 0)? Unless you are preventing zero-size vectors in some smart way, your operator should pay attention to that case.
More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity. --W.A.Wulf
Premature optimization is the root of all evil --Donald E. Knuth
Please read Information on posting before posting, especially the info on using [code] tags.
-
June 25th, 2009, 01:57 PM
#7
Re: Templated class and iostream overloading
Ok thanks, I know sometimes I should use standard code, but I wanted to do it to learn too... I'm a newbie C++ programmer and I still have to learn a lot... so that's why I wanted to write it myself, so I could learn from my own mistakes.
Operator [] must have two versions, a const and non-const version. I don't know if you provided it, but I'm preparing you for what could cause a problem once you start passing const references to your vector class.
I have made those modifications and it works, but I don't really understand why I need a constant version can you explain it please?
Otherwise, there is really no difference if the template function is inline or not inlined. The only thing you have to be aware of is that the non-lined version of the template function has to still "ride" with the template header, i.e., the code must be included at the end of the template declaration.
So can I get those operators with the rest of my operators inline inside the class definition?? If so can you tell me how?
Thanks for the help!!! It is really appreciated.
EDIT:
What if the vector is empty (size 0)? Unless you are preventing zero-size vectors in some smart way, your operator should pay attention to that case.
Yes i have dealt with vector size = 0 but thanks for pointing out i should take that in to count...
Thanks anyway for the help guys!
And the vector I am writing I think is pretty similar to the one in std::vector in its base form... but I'm planning to add Mathematical operators and functions to it.
Last edited by beta3designs; June 25th, 2009 at 02:01 PM.
-
June 25th, 2009, 06:39 PM
#8
Re: Templated class and iostream overloading
Originally Posted by beta3designs
I have made those modifications and it works, but I don't really understand why I need a constant version can you explain it please?
When you pass a const reference to an object, any function you call on that object must be const. So if you're passing a const reference to a mut::vector, and within that function you're calling operator [] (which is a member function of mut::vector), it must be const.
That is called const correctness in C++. When an entity is const, it is a contract that states that the entity will not be changed, else a compiler error will occur. You should study up as soon as possible on const correctness, as its one of the basics of writing proper C++ code. As a matter of fact, this should have been studied before writing one line of template code.
So can I get those operators with the rest of my operators inline inside the class definition?
What did you attempt? It's no different than writing other functions inline.
And the vector I am writing I think is pretty similar to the one in std::vector in its base form...
Given some of the errors you were making with the small bit of code, I think you better post your vector class because it is more than likely to have other issues that experienced C++ programmers would identify.
Regards,
Paul McKenzie
-
June 26th, 2009, 12:44 AM
#9
Re: Templated class and iostream overloading
Thanks for the explanation gonna check constant correctness right now... yeah I think it seems I forgot to learn some of the basics xD
Given some of the errors you were making with the small bit of code, I think you better post your vector class because it is more than likely to have other issues that experienced C++ programmers would identify.
Well that makes sense... anyway it works pretty well... but it may have some errors so I'll post it.
What did you attempt? It's no different than writing other functions inline.
Well don't know, first I tried to put it inline with the rest of my functions but it wasn't working some strange errors happened so I thought of taking it out, since it was an iostream operator and not a vector operator?
well I post my class so you can help me better
Code:
/*
MUT~ Math Utility Toolkit
Written by Alejandro Valero (a.k.a. beta3designs)
Copyright (c) 2009
Contact: beta3designs@gmail.com
This file is part of MUT.
MUT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
MUT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MUT. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*/
#ifndef MUT_VECTOR_H
#define MUT_VECTOR_H
#include <iostream>
namespace mut{
template <class T=int> //Default vector storage is int
class vector{
public:
//Create vector with defined size, zero if not defined
vector(int size = 0){
vlen = size;
vlist = new T[size];
//Check storage
assert(vlist != 0);
}
//Create vector with defined size and fill it
vector(int size, T fill){
vlen = size;
vlist = new T[size];
//Check storage
assert(vlist != 0);
for(int i = 0; i < size; i++){
vlist[i] = fill;
}
}
//Copy constructor
vector(const vector<T>& vector2){
vlist = new T[vlen = vector2.vlen];
//Check storage
assert(vlist != 0);
//Copy elements
for(int i = 0; i < vector2.vlen; i++){
vlist[i] = vector2.vlist[i];
}
}
//Vector's capacity
int length() const{
return vlen;
}
//Resize vector's capacity
void resize(int resizeto){
/*If the new size is bigger than the old size copy all
elements, else copy only new size elements*/
int num = resizeto < vlen ? resizeto : vlen;
T* newlist = new T[resizeto];
//Check storage
assert(newlist != 0);
//Loop through elements and copy them
for(int i = 0; i < num; i++){
newlist[i] = vlist[i];
}
//Delete old storage
delete[] vlist;
//Reassign storage
vlen = resizeto;
vlist = newlist;
}
//Fill vector with desired element
void fill(T fill){
for(int i = 0; i < vlen; i++){
vlist[i] = fill;
}
}
//Assignment operator
vector& operator=(const vector<T> &vector2){
//Check adress to prevent assigning to self
if(this!= &vector2){
/*Delete vector list and assign a new one with the same
size*/
delete[] vlist;
vlist = new T[vlen = vector2.vlen];
//Check storage
assert(vlist != 0);
//Copy vector components
vlen = vector2.vlen;
for(int i = 0; i < vlen; i++){
vlist[i] = vector2.vlist[i];
}
}
return *this;
}
//Index operator
T& operator[](int vindex){
/*Index must be positive or zero and smaller or equal than
vector's length*/
if(vindex < 0 || vindex >= vlen){
std::cerr << "Illegal vector index: " << vindex
<< ". Max index = "<< vlen -1 << std::endl;
assert(vindex < 0);
assert(vindex >= vlen);
}
return vlist[vindex];
}
//Constant overloaded index operator
const T& operator[](int vindex) const{
/*Index must be positive or zero and smaller or equal than
vector's length*/
if(vindex < 0 || vindex >= vlen){
std::cerr << "Illegal vector index: " << vindex
<< ". Max index = "<< vlen -1 << std::endl;
assert(vindex < 0);
assert(vindex >= vlen);
}
return vlist[vindex];
}
//Free memory and storage
~vector(){
delete[] vlist;
vlen = 0;
vlist = 0;
}
private:
T* vlist;
int vlen;
};
//IOSTREAM operators
template <class T>
std::ostream& operator<<(std::ostream& os, const vector<T> &vec){
if(vec.length() == 0) return os << "(0 size vector)" << std::endl;
int i = 0;
os << "(";
for(i = 0; i < vec.length() - 1; i++){
os << vec[i] << ", ";
}
os << vec[i] << ")" << std::endl;
return os;
}
template <class T>
std::istream& operator>>(std::istream& is, vector<T> &vec){
if(vec.length() == 0){
std::cerr << "Cannot take input, vector size = 0. Min size = 1"
<< std::endl;
}
int i = 0;
for(i = 0; i < vec.length(); i++){
is >> vec[i];
}
return is;
}
}
#endif // MUT_VECTOR_H
I think I should finish reading my C++ books before trying something this big... xD
-
June 26th, 2009, 02:51 AM
#10
Re: Templated class and iostream overloading
Originally Posted by beta3designs
Ok thanks, I know sometimes I should use standard code, but I wanted to do it to learn too... I'm a newbie C++ programmer and I still have to learn a lot... so that's why I wanted to write it myself, so I could learn from my own mistakes.
Don't try and take on too many new things at the same time, otherwise you'll get swamped by errors and concepts that you don't understand. Re-invent vector is you wish, as a learning exercise, but I think it would be better done as a separate exercise from your maths classes.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
June 26th, 2009, 03:02 AM
#11
Re: Templated class and iostream overloading
A small comment on the code:
Originally Posted by beta3designs
Code:
namespace mut{
template <class T=int> //Default vector storage is int
class vector{
public:
//Create vector with defined size, zero if not defined
vector(int size = 0) {
// ...
Such constructors should always be declared as explicit (using the explicit keyword), to prevent implicit conversion of an integer into a vector. It would be very counter-intuitive if 5 would be implicitly converted to a vector of size 5.
So, once you opened your C++ book again, look for explicit in the index
More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity. --W.A.Wulf
Premature optimization is the root of all evil --Donald E. Knuth
Please read Information on posting before posting, especially the info on using [code] tags.
-
June 26th, 2009, 04:13 AM
#12
Re: Templated class and iostream overloading
thanks for the tips
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|