Static methods vs local methods within a class - c++

First, to get my concern across take a look at these two code segments I have prepared:
struct Quaternion
{
public:
float X, Y, Z, W;
Quaternion(float x, float y, float z, float w)
:
X(x), Y(y), Z(z), W(w)
{}
void Normalise()
{
float num = (((this->X * this->X) + (this->Y * this->Y)) +
(this->Z * this->Z)) + (this->W * this->W);
float num2 = 1.0f / (static_cast<float>(std::sqrt(static_cast<double>(num))));
this->X *= num2;
this->Y *= num2;
this->Z *= num2;
this->W *= num2;
}
void Conjugate()
{
this->X = -this->X;
this->Y = -this->Y;
this->Z = -this->Z;
}
};
The above being the 'local methods' within the class that I am referring to in the title..
Now lets take a look at what I mean by the 'static methods' inside the class.
struct Quaternion
{
public:
float X, Y, Z, W;
Quaternion(float x, float y, float z, float w)
:
X(x), Y(y), Z(z), W(w)
{}
static Quaternion& Normalise(Quaternion& quat)
{
float num = (((quat.X * quat.X) + (quat.Y * quat.Y)) +
(quat.Z * quat.Z)) + (quat.W * quat.W);
float num2 = 1.0f / (static_cast<float>(std::sqrt(static_cast<double>(num))));
// Assuming operator= overloaded..
quat = Quaternion(quat.X * num2, quat.Y * num2, quat.Z * num2, quat.W * num2);
return quat;
}
static Quaternion& Conjugate(Quaternion& quat)
{
// Assuming operator= overloaded..
quat = Quaternion(-quat.X, -quat.Y, -quat.Z, quat.W);
return quat;
}
};
My question is.. What is the tradeoff? The effect? To using these static class methods rather than local methods. Both have similar usage:
Edit: Ignore the *.ToString functionality, it is psuedocode - I'm sure you can imagine what it would do; therefore its implementation is redundant as it just prints out raw X, Y, Z, W values.
The 'local method' class usage:
int main()
{
Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f);
std::cout << testQuat.ToString(); // (6, 6, 6, 1.3)
testQuat.Conjugate();
std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3)
return 0;
}
Now the 'static method' class usage:
int main()
{
Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f);
std::cout << testQuat.ToString(); // (6, 6, 6, 1.3)
testQuat = Quaternion::Conjugate(testQuat);
std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3)
return 0;
}
So what is the difference? These are static methods not objects. Which is preferable? Is it just a matter of design choice?

They are two totally different things. One of them modifies the object in place a la OOP, the other returns a different object a la functional style. If it was my choice, I would keep both of them as there are use cases for both of them. And I would implement the functional styles as free functions based on the member functions, i.e.:
Quaternion normalize( Quaternion quat )
{
quat.normalize();
return quat;
}
[I'm explicitly taking quat by value here, gives a chance for copy-elision]
Note that your static implementations are wrong, they are returning a reference to a temporary. That's undefined behavior, you should get a warning from your compiler and if you are lucky enough a runtime crash as well.

First off, your second approach shouldn't compile although I think MSVC++ has an error allowing temporary objects to be bound to non-const references. Even adding const& doesn't make the functions better: They still don't work because the caller gets hold of a reference to a temporary. So much for the implementation.
With respect to interface design, I think the real trade-off isn't between static members (you can have them additionally, if you want to) but whether the functions taking no parameters should mutate the object themselves or should return a correspondingly modified object:
// return a copy:
Quaternion Quaternion::conjugate() const {
return Quaternion(-this->X, -this->Y, -this->Z, this->W);
}
// modify the object itself:
void Quaternion::conjugate() {
this->X = -this->X;
this->Y = -this->Y;
this->Z = -this->Z;
}
Although these two overload actually can live in the same class I would not provide both of them! It is a choice of interface which one is preferable. I would personally prefer the latter and probably create a static member mutating the object itself:
/* static */ void Quaternion::conjugate(Quaternion& object) {
object = object.conjugate();
}

Besides the other answers about differences between the two approaches, the static methods are difficult to mock/stub if you want to employ in unit tests.
For example, suppose that you have a class named ClassThatUsesQuaternion that uses Quaternion. If Quaternion have a lot of static methods you will always have real data. On the other hand, if you transform Quaternion methods into virtual methods, you will be able to redefining all methods, creating a environment test under your control. You can even add a mock framework like gmock to put your expectations.

Related

How to cast one struct to another type with identical members?

If I'm given a struct variable like:
struct Quaternion {
float x;
float y;
float z;
float w;
}
But I need to call a function expecting a
struct Vector {
float x;
float y;
float z;
float w;
}
Is there a way in C++ to cast a variable of type Quaternion to type Vector?
You can write a converting constructor:
struct Quaternion {
float x;
float y;
float z;
float w;
explicit Quaternion(const Vector& vec) : x(vec.x),y(vec.y),z(vec.z),w(vec.w) {}
}
And similar for the other way.
In case you are looking for a way that does not require to copy the members, then I am not aware of a portable way to do that, and members having the same name does not help for that.
On the other hand, having same named members helps to write generic code like this:
template <typename T>
void foo(const T& t) {
std::cout << t.x << t.y << t.z << t.w;
}
You can call this with either a Quaternion or a Vector without needing to convert between them.
In case you cannot modify any existing code (not the structs nor the function you want to call), you can write a simple function to do the conversion (as suggested by ShadowRanger in a comment):
Vector Quat2Vect(const Quaternion& q) {
return {q.x,q.y,q.z,q.w};
}
If, as you said in a comment, you can't change to the two types, you could possibly "solve" the problem by using yet another type:
struct MyVector {
float x;
float y;
float z;
float w;
operator Quaternion() { return Quaternion{x, y, z, w}; }
operator Vector() { return Vector{x, y, z, w}; }
};
My advice: It's probably better to pick one or the other as the main type in your code and use a separate conversion function.
What I think you're hoping for, given that you specifically asked about "cast", is to use a cast to go from one to the other.
Vector v = {1, 2, 3, 4};
Quaternion* q = reinterpret_cast<Quaternion*>(&v);
do_something_with_quart(*q); // Could modify v if pass by reference
Strictly speaking, this is undefined behaviour, although it is overwhelmingly likely to work in practice, but I still wouldn't recommend it. If you're really desparate to do something cast like, it's legal to use memcpy so long as the member variables are the same type in the same order (and there are no virtual methods):
Vector v = {1, 2, 3, 4};
Quaternion q;
memcpy(&q, &v, sizeof(v));
do_something_with_quart(q);
memcpy(&v, &q, sizeof(v)); // Copy back any change
Although the language and documentation describes memcpy as a copying function, it has certain magical properties that often in practice make it identical to the previous block of code. But I would also strongly advise against this. I mean, yuck! Just look at it!!
This is just an addition to largest_prime_is_463035818's answer to point out that the members don't have to have the same name in order to write a generic function to use them. So long as there are an equal number of members, all are publicly accessible, and they have the same types, you can decompose objects with a structured-binding and use that.
template <typename T>
void foo(const T& t) {
auto const & [x, y, z, w] = t;
std::cout << x << y << z << w;
}

C++ float value of a local variable explanation?

I have a simple math vector struct
struct vec3d {
float x;
float y;
float z;
float w;
public:
vec3d(float a, float b, float c) { a = x; b = y; c = z; w = 1; }
vec3d() { x = 0; y = 0; z = 0; w = 1; }
};
With the following operation in a function (I am not using operator overloading)
vec3d vsubvector(vec3d& v1, vec3d& v2)
{
return vec3d(v1.x - v2.x, v1.y - v2.y,v1.z - v2.z);
}
I am using it inside the main function within a loop block like this
{
...
vec3d normal, line1, line2;
line1 = vsubvector(p[1], p[0]);
line2 = vsubvector(p[2], p[0]);
normal = vcrossproduct(line1, line2);
normal = vnormalise(normal);
...
}
Here p is an array of three vectors
Now while debugging, when I enter the block where the local variable is defined, line1.x, line1.y and line1.z are assigned a big signed float value (-107374176.0f) and they do not change after the subtract function is returned into them.
What is the reason that vsubvector function is not working?
vec3d(float a, float b, float c) { a = x; b = y; c = z; w = 1; }
Is assigning to the constructor arguments from the uninitialised member variables. Obviously wrong. You'd want to reverse the order of assignment.
Additionally, you should use the constructors initialization list to initialize members rather than the constructor body. Do this:
vec3d(float a, float b, float c) : x(a), y(b), z(c), w(1) { }
For basic types like ints or floats it makes little difference, but for user defined types it can make a big difference. It is wasteful to first let the constructor default initialize members and then subsequently assign to them in the constructor body. Also, for some types, doing so is not even possible, not all types support assignment so initialization is the only option.
Additionally, the default constructor vec3d() can delegate to the other constructor:
vec3d() : vec3d(0.f, 0.f, 0.f) {}

Address of local variable returned--can ignore warning without detriment but what's the proper way?

I have a class Particle:
class Particle {
private:
float x, y, z;
// ...
public:
// ...
float* getPos() {
float p[3] = {x, y, z};
return p;
}
// ...
};
I would call this method like:
Particle a = Particle();
// ...
float* pos = a.getPos();
And then reference the position elements with pos[0] through pos[2].
g++ spouts warning message as stated in the title. But the functionality is exactly how I want it: returning an array. Why does the warning exist and is there a "proper" way to do it?
You can't return a C-array like that, return std::array instead:
std::array<float, 3> getPos() {
std::array<float, 3> p = {x, y, z};
return p;
}
You'll need to include <array> for that.
Personally, I'd skip std::array/std::vector here, because in your particular case, the position of each value imposes independent meaning. In general, sequence types have ordering, tuples have structure; if the element count is fixed (and often heterogeneous) and sorting (or otherwise reordering the values) is intrinsically nonsensical (e.g. in the case of a coordinate, swapping the x and y values changes the meaning), then a tuple makes more sense.
In this case, you could just declare:
std::tuple<float, float, float> getPos() {
// C++17 or higher allows list initialization
return {x, y, z};
// Pre-C++17 you use the std::make_tuple helper
return std::make_tuple(x, y, z);
}
The advantage here is that you can then unpack the result in the caller easily, either with std::tie:
float x, y, z;
std::tie(x, y, z) = a.getPos();
or on C++17 or higher with structured bindings, it's even nicer, since you can declare and initialize the variables with auto, rather than declaring with explicit types, then reassigning with tie:
auto [x, y, z] = a.getPos();
You can store the tuple itself and use std::get if you prefer, but unpacking to useful names rather than obscure std::get indices usually makes for much cleaner code.
You're not returning an array. It's impossible to return an array in C++. You're returning a pointer to an array which no longer exists. Hence the warning.
You could make the array a part of your class and return a pointer to that. In general I wouldn't call that good design
class Particle {
private:
float pos[3];
// ...
public:
// ...
float* getPos() {
return pos;
}
// ...
};
You could return a vector<float> instead. You could return an array<float,3> instead. You could ask yourself why you need this.
p[3] will be destroyed when it goes out of scope so you shouldn't return a pointer to it.
Either return a std::array<float, 3> by value or consider making a class for positions too, and return a Position object, or a reference to it. Example:
struct Position {
float x, y, z;
};
class Particle {
private:
Position m_pos;
// ...
public:
// ...
Position const& getPos() const { return m_pos; }
// ...
};
I'd suggest that you're function is indicative of poor design. Provide getter methods an allow the user of your class to access member variables:
class Particle {
private:
float x, y, z;
public:
float GetX() const { return x; }
float GetY() const { return y; }
float GetZ() const { return z; }
};
Given const Particle a this will let you initialize an array as follows: const float pos[] = { a.GetX(), a.GetY(), a.GetZ() }
Creating a Particle method to allow the user to populate a float[] will encourage the user toward one of the following bad practices:
float* Particle::GetPos() const { return new[3]{ x, y, z }; } creates dynamic memory without clearly informing the caller that the memory needs to be released
array<float, 3U> Particle::GetPos() const { return { x, y, z }; } requires the allocation and creation of a temporary to populate a float[]
void Particle::GetPos(float* param) const { param[0] = x; param[1] = y; param[2] = z; } misses the opportunity for constant arrays and incurs potential caller misuse, as it's not clear that param must have room for at least 3 floats

C++ pointer wrong value

Relatively new to C++, I'm trying to learn using dynamic memory. In this case I'm using it to store member variables.
Quanternion.h -
#ifndef QUATERNION_H_
#define QUATERNION_H_
class Quaternion
{
private:
double* x = new double();
double* y = new double();
double* z = new double();
double* w = new double();
public:
Quaternion(double x, double y, double z, double w);
Quaternion(const Quaternion& q);
Quaternion& operator=(const Quaternion& q);
~Quaternion();
void setQ(double *_x, double *_y, double *_z, double *_w);
double * getX() { return x; }
double * getY() { return y; }
double * getz() { return z; }
double * getw() { return w; }
};
#endif
Quanternion.cpp -
#include "Quaternion.h"
Quaternion::Quaternion(double x, double y, double z, double w)
{
double*a = &x;
double*b = &y;
double*c = &z;
double*d = &w;
setQ(a,b,c,d);
}
Quaternion::Quaternion(const Quaternion & q)
{
this->x = q.x;
this->y = q.y;
this->z = q.z;
this->w = q.w;
}
Quaternion & Quaternion::operator=(const Quaternion & q)
{
if (this == &q)
{
return *this;
}
this->x = q.x;
this->y = q.y;
this->z = q.z;
this->w = q.w;
return *this;
}
Quaternion::~Quaternion()
{
}
void Quaternion::setQ(double *_x, double *_y, double *_z, double *_w)
{
this->x = _x;
this->y = _y;
this->z = _z;
this->w = _w;
}
When I create a Quaternion object and set the fields, and try and print one of the variables such as X by deallocating a pointer. I do not get the result I am expecting.
int main()
{
Quaternion q1(4, 9, 2, 5);
double*d = q1.getX();
cout << d << endl;
cout << *d << endl;
}
Example output -
00B1FB5C
6.26381e+148
Where am I going wrong?
Your code violates basic principles of managing raw pointers - you have no idea who owns them. The same pointer might be an allocated entity through new, or simply an address provided in the constructor. That makes owning those impossible - you can't write assignment operators or copy constructors (your current implmentation is wrong).
The more immediate problem is that you are remembering address of arguments in your 4-doubles constructor. This is the immediate cause for dangling pointer and undefined behavior.
If you want to learn how to use pointers, you need to read a book about it. If you simply need to use pointer-like semantics, use smart pointers.
I am pretty sure you're compiler gave you some warnings. In your constructor, you take the address of of the four initializer arguments x, y, z and w.
This is allowed, but only for using the address inside the constructor function itself. Because when the constructor function is done, these variables are not valid anymore, and therefore, pointers to them point to an invalid memory address (you don't know what's there anymore).
You have two options:
don't use pointers; in this class you don't need them. Copying a pointer takes just as much work as copying a double.
manage your pointers yourself. Create four new doubles in your constructor, and change their value. It might also be nice to look up refreneces.
I understand that you are trying to learn about pointers, but for this applications, pointers are really not necessary. And only make things slower. (Although not much).
you don't have implementation of setQ here
You are trying to pass by value and getting the address of the value in
Quaternion(double x, double y, double z, double w)
When You are trying to pass by value in Quaternion (double x, double y, double z, double w), You get the address of the value. After exit Quaternion (double x, double y, double z, double w) addresses are engaged in these variables are cleared away, and you are using is not your memory.

C++ access multiple members by array

Lot's of year from last project in C++, I cannot remember/find how to do this.
Sample (pseudo code) :
MyClass
{
public :
float x;
float y;
float z;
}
main.cpp
void MyFunction(void)
{
MyClass *myclass = new MyClass();
float x = myclass->x;
//want I want :
float *xyz = myclass->xyz;
}
How to do this ?
Thank you very much and sorry for my poor english.
[EDITED]
It's only a concept now, but the goal, is near the vec4 class in GLSL (OpenGL Shader for GPU). Vec4 is a math vector class with four values (x, y, z, w). You can get/assign value like this sample :
vec4 vectorA = vec4(1.0, 1.0, 1.0, 1.0);
vectorA.x = 2.0;
vec2 vectorB = vectorA.xy;
vec3 vectorC = vectorA.xxx;
etc. (so : VectorC.x = 2.0, vectorC.y = 2.0, vectorC.z = 2.0)
Use unnamed structure:
union Vector
{
struct
{
float x;
float y;
float z;
};
float xyz[3];
};
Then you can access components without implicitly referencing containing structure:
int main()
{
Vector* vec = new Vector();
vec->x = 50;
vec->y = 30;
vec->xyz[2] = vec->xyz[0] + vec->xyz[1]; // vec->z == 80
delete vec;
return 0;
}
Of course, you can wrap this union with another structure/class, to same effect:
class MyClass
{
public:
union
{
struct
{
float x;
float y;
float z;
};
float xyz[3];
};
};
Also, why create your structure on heap (using "new")? Won't allocating on stack do?
EDIT: Oh, I get it. Well, it's definitely doable, but it is worth it only if you want as much compability with GLSL as possible. The idea is to create a "proxy" that stores references for each component variation. The tradeof is that vec2, instead of taking 8 bytes of memory will take 40 bytes. It will obviously get much, much worse for vec3 & vec4
class vec2
{
// private proxy, auto-convertible into vec2
struct proxy2
{
// store references, not values!
proxy2(float &x, float &y) : x(x), y(y) {}
// implicit conversion to vec2
operator vec2() { return vec2(x, y); }
// support assignments from vec2
proxy2& operator=(const vec2& vec)
{
x = vec.x;
y = vec.y;
return *this;
}
private:
// hide copy and assignment operators
proxy2(const proxy2&);
proxy2& operator=(const proxy2&);
// hide member variables
float& x;
float& y;
};
public:
vec2(float _x, float _y)
: x(_x), y(_y)
, xx(x, x), xy(x, y), yx(y, x), yy(y, y)
{}
vec2(const vec2& vec)
: x(vec.x), y(vec.y)
, xx(x, x), xy(x, y), yx(y, x) , yy(y, y)
{}
float x;
float y;
proxy2 xx;
proxy2 xy;
proxy2 yx;
proxy2 yy;
};
With this class you can get syntax pretty close to what GLSL offers:
vec2 v(1.0f, 2.0f);
vec2 vxx = v.xx; // 1, 1
vec2 vyx = v.yx; // 2, 1
vec2 vxy = v.xy; // 1, 2
vec2 vyy = v.yy; // 2, 2
v.yx = vec2(3, 4); // 4, 3
v.y = 5; // 4, 5
vec2::proxy2 proxy = v.xx; // compile error
v.xx = vec2::proxy2(v.x, v.y); // compile error
To extend this to support vec3 and vec4 simply derive from vec2 and vec3 respectively, create proxy3 and proxy4 structs and declare member for each component variation (27 for vec3 and mere 64 for vec4).
EDIT2: New version, that does not take extra space at all. Again, unions to the rescue! Converting proxy2 to a template and adding data member that matches vec2 components you can safely put it into an union.
class vec2
{
// private proxy, auto-convertible into vec2
template <int x, int y>
struct proxy2
{
// implicit conversion to vec2
operator vec2()
{
return vec2(arr[x], arr[y]);
}
// support assignments from vec2
proxy2& operator=(const vec2& vec)
{
arr[x] = vec.x;
arr[y] = vec.y;
return *this;
}
private:
float arr[2];
};
public:
vec2(float _x, float _y)
: x(_x), y(_y)
{}
vec2(const vec2& vec)
: x(vec.x), y(vec.y)
{}
union
{
struct
{
float x;
float y;
};
proxy2<0, 0> xx;
proxy2<0, 1> xy;
proxy2<1, 0> yx;
proxy2<1, 1> yy;
};
};
Hope this is what you are after.
EDIT3: I took me a while, but I came up with a working GLSL emulation library (includes swizzling) allowing you to run fragment shaders without modifications. If you are still interested, you should take a look.
C++ can accommodate syntax like vec.xyx, but it's not easy to write. And you won't get there by adding features one by one. It's better to list the requirements, select the tools, and make a straight shot.
What you need:
A storage class like std::array
Members named x, y, … xy, xz, … xyz, xzx, …
Something that converts those members to the desired output
Types to give the output the desired semantics
The first requirement is simple: use std::array.
Next you have to define 3 + 3^2 + 3^3 = 39 members. This can be done by copy-paste but you're better off with template metaprogramming. With a z member it's a must.
The types of the members are meaningless, but must tell the compiler how to choose the named elements from the array.
Example:
selection_vector< 0, 1, 0 > xyx;
selection_vector< 0, 1, 1 > xyy; // ad nauseam
Ideally these members would know how to select the elements with no state, but they will need to be initialized with this and take up one pointer each. So be aware that each 3-vector object wastes 312 bytes.
To make the members do something, you have to define conversion functions. So you have something like
selection_vector::operator array3_type() { return { ptr[0], ptr[1], ptr[2] }; }
Implicit conversion functions apply when performing assignment and passing as a function argument besides this, but not in many other situations. So to obtain vec.xyx.x or vec.xyx[ 1 ] the selection_vector type would need to define additional members.
Once you've defined the web of crazy types and operator overloads, you'll be able to save a few keystrokes…
Minor compromise
It sounds like you don't really want to compromise, but the ->* operator is worth mentioning. It's the best non-member operator overload for implementing subscripts.
This allows a pattern like
xyx_type xyx;
template< typename vec >
my_3vector< vec > operator->* ( vec &&v, xyx_type )
{ return { v[0], v[1], v[2] }; }
std::array< float, 3 > a { 0.5, 1.5, 9 };
my_3vector< … > b = a->*xyx;
You could even make my_3vector simply std::array and avoid any template metaprogramming. Make xyx_type an enumeration to avoid preprocessor metaprogramming too.
The ->* operator stands in for .. This makes things a lot easier, but note that ->* has funny precedence; it's lower than . and -> whereas you would expect it to be a peer.
Here is another solution possible, a slight variation to union-based example posted by #gwiazdorrr. It assumes
#include <cassert>
#include <algorithm>
#include <stdexcept>
struct MyClass
{
enum { size = 3 };
typedef float& reference;
reference x;
reference y;
reference z;
MyClass()
: x(xyz[0] = 0), y(xyz[1] = 0), z(xyz[2] = 0)
{}
MyClass(float x, float y, float z)
: x(xyz[0] = x), y(xyz[1] = y), z(xyz[2] = z)
{}
MyClass& operator=(MyClass const& other)
{
std::copy(other.xyz, other.xyz + size, xyz);
return *this;
}
// convenient indexed access
reference operator[](std::size_t index)
{
if (index < size)
return xyz[index];
else
throw std::out_of_range("index not less than size");
}
// raw data access
float* data() { return xyz; }
private:
float xyz[size];
};
int main()
{
MyClass c1;
MyClass c2(1, 2, 3);
c1 = c2;
assert(c1.data()[0] == c2[0]);
assert(c1.data()[1] == c2[1]);
assert(c1.data()[2] == c2[2]);
MyClass c3(c2);
assert(c2[0] == c3.x);
assert(c2[1] == c3.y);
assert(c2[2] == c3.z);
}
I assumed no access to C++11, thus the initialisation gymnastics in the constructors.