I'm trying to create a custom vector class for use in doing linear algebra calculations in my programs. The class name for now is Rvec. Here's what I'm attempting:
I want to be able to reference elements in my vector by index BUT, also want to be able to access the first three elements (x,y,z) by typing .x after an object name (like if I had and Rvec named V, I could access element 0 by typing V.x and similar for y and z) because that makes it much more easy to follow in some of my programs. I've been thinking about this for a while and also couldn't find any definitive answers online but though of a few ideas that all ended in failure.
I also overloaded the [] operator so that you can access elements directly (V[0] instead of V.values[0])
class Rvec {
public:
std::vector<float> values;
float operator[] (int index) { return values[index]; }
//option 1
//float x, y, z = values[0], values[1], values[2];
/* option 2
float* x = &values[0];
float* y = &values[1];
float* z = &values[2];
// *Rvec.x
*/
/* option 3
#define x values[0]
#define y values[1]
#define z values[2]
// Rvec.x
*/
// option 4
/* std::map<char, float> m;
Rvec() {
m.insert(pair<char, float>('x', 0));
m.insert(pair<char, float>('y', 0));
m.insert(pair<char, float>('z', 0));
}
float operator[](int index) {return m.at(index);}
float operator[](char key) { return m[key]; }*/
};
The first option would just to be initialize x,y,z as floats, but that clearly wont work because they won't update their values when the actual elements do.
The second option would be to define x,y,z as float pointers but then I would need to access them by typing *V.x and so on and that isn't the thing I'm going for.
The third option would be to #define x,y,z as macros. But, that comes with its own issues that I don't want to deal with.
The final option might be to use a map and initialize the keys to the first three elements as x,y,z. But then to reference them after overloading it would be V['x'] which is even worse than pointers.
Is there any way to be able to reference elements like this just typing V.x and the value always being the same as the element it corresponds to?
CodePudding user response:
I recommend using some getters and setters:
class Rvec
{
public:
// getter
float x() const
{ return values[0];}
// setter
void x(float new_value)
{ values[0] = new_value;}
// If you trust the callers you return a reference:
float& y()
{ return values[1]; }
};
This would appear in code as:
Rvec r;
//...
std::cout << r.x() << "\n";
float f = 0.0;
std::cout << "Enter x value: ";
std::cin >> f;
r.x(f);
std::cout << "Enter y value: ";
std::cin >> r.y();
The syntax may not be as elegant as other languages that support properties, but it should resolve your issue.
Note: if the last pair of statements doesn't work try this:
std::cout << "Enter y value: ";
std::cin >> f;
r.y() = f;
The last statement is valid since the r.y()
returns a reference to a vector slot.
CodePudding user response:
A good solution that was given by @super in the comments:
create x,y,z as regular float, use the values vector for all elements past the first three, then make the [] operator fetch the correct variable depending on index.
class Rvec {
public:
float x, y, z;
std::vector<float> values;
float operator[] (int index) {
switch (index) {
case 0:
return x;
case 1:
return y;
case 2:
return z;
default:
return values[index - 3];
}
}
};