overloading the [] operator in a vector child class

Y

y-man

Hi,

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:

---xyzvec.hh--
#ifndef XYZVEC_HH
#define XYZVEC_HH

#include <vector>
#include <iostream>

xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].

My class is now:

class xyzvec : public vector<double> {

public:
xyzvec( void ) : vector<double>(3) { }

xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}

double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }

double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;
}
private:


} ;

#endif
 
?

=?iso-8859-1?q?Erik_Wikstr=F6m?=

Hi,

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:

---xyzvec.hh--
#ifndef XYZVEC_HH
#define XYZVEC_HH

#include <vector>
#include <iostream>

xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].

My class is now:

class xyzvec : public vector<double> {

public:
xyzvec( void ) : vector<double>(3) { }

xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}

double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }

double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;}

private:

} ;

#endif

I'm not an expert on inheritance but I don't think it works the way
you want to with the standard containers, try instead to keep a vector
as a member.
 
S

Stuart Redmann

y-man said:
Hi,

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:

---xyzvec.hh--
#ifndef XYZVEC_HH
#define XYZVEC_HH

#include <vector>
#include <iostream>

xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].

My class is now:

class xyzvec : public vector<double> {

public:
xyzvec( void ) : vector<double>(3) { }

xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}

The compiler complains that it doesn't find an operator[] with unsigned int
arguments (more correctly of type std::vector<double>::size_type). As you have
defined an operator[] in your derived class, this operator hides all operator[]
definitions of the base class (for whichever reason, I personally think that
this should be a bug in the language specification as this is contrary to common
sense and has no positive effect I can think of). To tell the compiler that
there is another operator[] in the base class you have to put the statement
using vector<double>::eek:perator[]; in your class declaration (preferably at the
very beginning of the class declaration).

double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }

double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;

You certainly mean return &(*this)[1] and &(*this)[2] in the last two cases.
}
private:


} ;

#endif

Probably I am doing something horribly wrong with the pointers, but
this yields a big heap of errors.

Nope. It works all right if you correct above errors.
BTW, why don't you simply add three member functions
double& x ();
double& y ();
double& z ();
that let you assign to the components x, y, and z? You would have to make the
existing member functions x (), y (), and z () to const members, of course.

Regards,
Stuart
 
Y

y-man

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:
---xyzvec.hh--
#ifndef XYZVEC_HH
#define XYZVEC_HH
#include <vector>
#include <iostream>
xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].
My class is now:
class xyzvec : public vector<double> {
public:
xyzvec( void ) : vector<double>(3) { }
xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}
double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }
double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;}

} ;
#endif
---

Probably I am doing something horribly wrong with the pointers, but
this yields a big heap of errors.

I'm not an expert on inheritance but I don't think it works the way
you want to with the standard containers, try instead to keep a vector
as a member.

It seems to work when I overload the "*"-operator... Is that a
different thing then?
 
S

Stuart Redmann

Stuart said:
y-man said:
Hi,

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:

---xyzvec.hh--
#ifndef XYZVEC_HH
#define XYZVEC_HH

#include <vector>
#include <iostream>


xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].

My class is now:

class xyzvec : public vector<double> {

public:
xyzvec( void ) : vector<double>(3) { }

xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}


The compiler complains that it doesn't find an operator[] with unsigned
int arguments (more correctly of type std::vector<double>::size_type).
As you have defined an operator[] in your derived class, this operator
hides all operator[] definitions of the base class (for whichever
reason, I personally think that this should be a bug in the language
specification as this is contrary to common sense and has no positive
effect I can think of). To tell the compiler that there is another
operator[] in the base class you have to put the statement
using vector<double>::eek:perator[]; in your class declaration (preferably
at the very beginning of the class declaration).

double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }

double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;

Here is another error: The correct operator should look like the following:

double& operator[] (const string& p_string)
{
if (p_string.compare ("x") == 0)
return (*this)[0];
if(p_string.compare ("y") == 0)
return (*this)[1] ;
if(p_string.compare ("z") == 0)
return (*this)[2] ;
// TODO: Throw an exception?
}

You certainly mean return &(*this)[1] and &(*this)[2] in the last two
cases.
}
private:


} ;

#endif

Probably I am doing something horribly wrong with the pointers, but
this yields a big heap of errors.


Nope. It works all right if you correct above errors.
BTW, why don't you simply add three member functions
double& x ();
double& y ();
double& z ();
that let you assign to the components x, y, and z? You would have to
make the existing member functions x (), y (), and z () to const
members, of course.

Regards,
Stuart
 
S

Stefan Naewe

Hi,

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:

---xyzvec.hh--
#ifndef XYZVEC_HH
#define XYZVEC_HH

#include <vector>
#include <iostream>

xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].

My class is now:

class xyzvec : public vector<double> {

public:
xyzvec( void ) : vector<double>(3) { }

xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}

double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }

double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;
}
private:


} ;

#endif

I wouldn't use a vector<> as a base class (in this case). You don't need
a dynamic container.

What's wrong with this:


class xyzvec
{
public:
// ...
private:
double x, y, z;
};



??

S.
 
M

Markus Moll

Hi

y-man said:
I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. [...]
My class is now:

class xyzvec : public vector<double> {

It should probably read "std::vector<double>".
Deriving publicly from std::vector is a bad idea if you impose
additional restrictions. In your case, you want the vector to always be
of size three. But one could easily do:

xyzvec x;
std::vector<double> y; // empty vector
y.swap(x); // hell breaks loose

Why don't you just use three member doubles?
double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }

Personally, I would prefer const and non-const versions returning const
references and non-const references, respectively.
double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;

return std::sqrt( x()*x() + y()*y() + z()*z() );
is more readable in my opinion (and likely to perform better)
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;
}

1. string is a type (I hope... you never included <string> and said you
were using std::string), not an object...
2. You declare operator[] to return a reference, but you actually try to
return pointers
3. You return the same pointer in any case.
private:


} ;

why "private:" if nothing follows?


Markus
 
P

Paul Holden

Hi,

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:
-snip-

xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].

-snip-

Accessing components of the vector (coordinate vector rather than
std::vector) in this way is going to be horribly inefficient - this
certainly isn't going to be a practical solution for realtime 3d use.
Every time you need to access a component of the vector you have to
construct a std::string instance (which may or may not involve dynamic
memory allocation depending on your compiler's STL implementation) and
perform 1-3 string comparisons.
class xyzvec : public vector<double> {

I don't think it's a good idea to publically derive from
vector<double> as, it lets users of your class adjust the vector
behind your back:

xyzvec vec ;
vec["x"] = 3;
vec.clear(); // Naughty
vec["z"] = 2; // Undefined behaviour! Crash?

In fact, as you know your xyzvec will always have 3 components,
there's no need to derive/use std::vector<> at all:

class xyzvec
{
public:
double x() const { return x; }
double y() const { return y; }
double z() const { return z; }

double operator[](int i)
{
if(i == 0) return x;
if(i == 1) return y;
if(i == 2) return z;

// ASSERT/throw exception etc
}

private:
double x, y, z;
}

Whatever solution you choose for your operator[] overload can be
implemented in terms of x/y/z.
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
2],2),0.5) ;
return n;

Finally I'd strongly suggest you avoid using pow() to square values
and perform square roots. Using pow(x, 2.0) is going to be many times
slower than (x*x) on most hardware. pow(x, 0.5) is very likely to be
slower than sqrt(x) too.

Paul
My class is now:

class xyzvec : public vector<double> {

public:
xyzvec( void ) : vector<double>(3) { }

xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}

double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }

double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;}

private:

} ;

#endif
 
J

Jim Langston

y-man said:
Hi,

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:

---xyzvec.hh--
#ifndef XYZVEC_HH
#define XYZVEC_HH

#include <vector>
#include <iostream>

xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].

My class is now:

class xyzvec : public vector<double> {

public:
xyzvec( void ) : vector<double>(3) { }

xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}

double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }

double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;
}
private:


} ;

#endif

I can see absolutly no benifit in deriving this class from vector then
either storing a normal array or a vector internal to the class. Even then,
you could just use a simple class. Since this is rather trivial I decided
to write and test one to see how I would do it:

#include <iostream>
#include <string>
#include <cmath>

class xyz
{
public:
xyz(): x_(0), y_(0), z_(0) {}
xyz( double x, double y, double z ): x_(x), y_(y), z_(z) {}
double& operator[] ( const std::string& dim )
{
if ( dim.length() == 1 )
return (*this)[dim[0]];
else
throw "Bad length of dimention requested";
}
double& operator[] ( char dim )
{
if ( dim == 'x' || dim == 'X' )
return x_;
else if ( dim == 'y' || dim == 'Y' )
return y_;
else if ( dim == 'z' || dim == 'Z' )
return z_;
else
throw "Bad dimention requested";
}
double& operator[] ( int dim )
{
if ( dim == 0 )
return x_;
else if ( dim == 1 )
return y_;
else if ( dim == 2 )
return z_;
else
throw "Bad dimention requested";
}
double length( )
{
return std::pow(std::pow(x_,2) + std::pow(y_,2) +
std::pow(z_,2),0.5) ;
}
private:
double x_;
double y_;
double z_;
};

int main()
{
xyz vec1;
vec1["x"] = 3;
double testing = vec1["x"];
std::cout << testing << "\n";

xyz vec2( 5, 10, 15 );
std::cout << vec2[0] << " " << vec2['y'] << " " << vec2["Z"] << " - " <<
vec2.length() << "\n";

std::string wait;
std::getline( std::cin, wait );

}

Now it becomes simple to add functionality. Your length is rather
arbitrary, since it seems to calculate the distnace from 0,0,0 to this
point. It seems more useful to calculate the distance between two points
(if you need the math I can provide it, it's fairly simple though).

What functionality did you wish to provide that vector gives you that this
simple class doesn't give you?
 
P

Paul Holden

Your length is rather
arbitrary, since it seems to calculate the distnace from 0,0,0 to this
point. It seems more useful to calculate the distance between two points
(if you need the math I can provide it, it's fairly simple though).

It's not really arbitrary - it's the standard definition of the length
of a 3-dimensional vector in Euclidean space:

http://en.wikipedia.org/wiki/Vector_(spatial)#Length_of_a_vector

xyz can be used to represent both vectors and points so you'd probably
want to provide both length(), and a distance() function as you
suggest.

[The length of the distance between two points would just be the
length of the vector between them - e.g.

double distance( const xyz & b ) const
{
xyz diff( a.x - b.x, a.y - b.y, a.z - b.z );
return diff.length();
}

Of course you could make this slightly cleaner by providing overloads
for operator-(const xyz &) etc.

]

Incidentally, it's probably worth the original poster running a Google
Codesearch (http://www.google.com/codesearch) for 'vector3 lang:"c++"'
as this problem has already been solved hundreds of times!

Paul
 
J

Jim Langston

Paul Holden said:
It's not really arbitrary - it's the standard definition of the length
of a 3-dimensional vector in Euclidean space:

http://en.wikipedia.org/wiki/Vector_(spatial)#Length_of_a_vector

Hmm, yes, you are right. I sometimes forget the actual meanting of vector
because in 3d graphics (such as DirectX) both vectors and vertexes are
stored in Vector structors, and it is much more common to store vertexes in
these structures I tend to associate a Vector with a 3d point when that's
actually the definition of a Vertex.

It makes me wonder, why they don't call the structures Vertex instead of
Vector as that is the most common data stored in them.
xyz can be used to represent both vectors and points so you'd probably
want to provide both length(), and a distance() function as you
suggest.

[The length of the distance between two points would just be the
length of the vector between them - e.g.

double distance( const xyz & b ) const
{
xyz diff( a.x - b.x, a.y - b.y, a.z - b.z );
return diff.length();
}

Of course you could make this slightly cleaner by providing overloads
for operator-(const xyz &) etc.

]

Incidentally, it's probably worth the original poster running a Google
Codesearch (http://www.google.com/codesearch) for 'vector3 lang:"c++"'
as this problem has already been solved hundreds of times!
 
Y

y-man

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:
-snip-

xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].

-snip-

Accessing components of the vector (coordinate vector rather than
std::vector) in this way is going to be horribly inefficient - this
certainly isn't going to be a practical solution for realtime 3d use.
Every time you need to access a component of the vector you have to
construct a std::string instance (which may or may not involve dynamic
memory allocation depending on your compiler's STL implementation) and
perform 1-3 string comparisons.
class xyzvec : public vector<double> {

I don't think it's a good idea to publically derive from
vector<double> as, it lets users of your class adjust the vector
behind your back:

xyzvec vec ;
vec["x"] = 3;
vec.clear(); // Naughty
vec["z"] = 2; // Undefined behaviour! Crash?

In fact, as you know your xyzvec will always have 3 components,
there's no need to derive/use std::vector<> at all:

class xyzvec
{
public:
double x() const { return x; }
double y() const { return y; }
double z() const { return z; }

double operator[](int i)
{
if(i == 0) return x;
if(i == 1) return y;
if(i == 2) return z;

// ASSERT/throw exception etc
}

private:
double x, y, z;

}

Whatever solution you choose for your operator[] overload can be
implemented in terms of x/y/z.
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
2],2),0.5) ;
return n;

Finally I'd strongly suggest you avoid using pow() to square values
and perform square roots. Using pow(x, 2.0) is going to be many times
slower than (x*x) on most hardware. pow(x, 0.5) is very likely to be
slower than sqrt(x) too.

Paul
My class is now:
class xyzvec : public vector<double> {
public:
xyzvec( void ) : vector<double>(3) { }
xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}
double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }
double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;}

} ;
#endif
---

Probably I am doing something horribly wrong with the pointers, but
this yields a big heap of errors.

Ah. Thanks to all of you. I am now just making the class in the way
you advise me to.

I am still making my string map because I do not want to use it at all
to use it in 3d realtime.
 
T

terminator

Hi,

I am creating a child class of the vector, which contains a couple of
functions to make the work with carthesian coordinate vectors easier.
To make things work more easily, I would like to be able to access the
vector through a string which is either x, y or z. So that I can use:

---xyzvec.hh--
#ifndef XYZVEC_HH
#define XYZVEC_HH

#include <vector>
#include <iostream>

xyzvec vec ;
vec["x"] = 3;
double testing = vec["x"].

My class is now:

class xyzvec : public vector<double> {

public:
xyzvec( void ) : vector<double>(3) { }

xyzvec(double x, double y, double z) : vector<double>(3) {
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}

double x() { return (*this)[0] ; }
double y() { return (*this)[1] ; }
double z() { return (*this)[2] ; }

double length( void ) {
double n = pow(pow((*this)[0],2) + pow((*this)[1],2) + pow((*this)
[2],2),0.5) ;
return n;
}
double& operator[] (const string&) {
if(string=="x") return &(*this)[0] ;
if(string=="y") return &(*this)[0] ;
if(string=="z") return &(*this)[0] ;}

private:

} ;

#endif

mathematical ,phisycal and C++ vector are three different concepts.Do
not confuse them .You need not inherit.You can do this:

enum subscript{x=0,y=1,z=2};
typedef double xyzvec[3];
xyzvec v;
v[x]=v[2]+v[y];
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,196
Latest member
ScottChare

Latest Threads

Top