Single-data components in ECS with inheritance : downsides? - c++

Let's say I have a component Position. This component has only one data, its... position. So it could be defined as this:
struct Position
{
Vector2 value;
};
But it's really redondant in access like entity.getComponent<Position>.value = {x, y};so I end up doing like so:
struct Position : Vector2
{
};
Is there any downside of doing this (syntacticly speaking) or some deviance related to the hypotetic ECS holy bible?

This solution is not canonical, but you can overload the "->" operator in order to access the fields of the child structure, but then you will have to take this into account if you pass Position by pointer to any functions. It is better to pass Position always by reference, then there will be no ambiguity. Operators "." and "::" cannot be overloaded, so it will not be possible to overload the behavior of p.x or p::x.
Here is an example code:
#include <iostream>
struct Vector2
{
float x = 0, y = 0;
};
struct Position
{
Vector2* const operator ->()
{
return &value;
}
Vector2 value;
};
int main()
{
Position p;
p->x = 1;
p->y = 2;
std::cout << p.value.x << " " << p.value.y << std::endl; // prints "1 2"
Position& pref = p;
pref->x = 3;
pref->y = 4;
std::cout << p.value.x << " " << p.value.y << std::endl; // prints "3 4"
Position* pp = &p;
(*pp)->x = 5;
(*pp)->y = 6;
std::cout << p.value.x << " " << p.value.y << std::endl; // prints "5 6"
return 0;
}

Related

C++ accessing class array pointer in a pointer to a structure

I am new to C++ and I really need some help on this. I am trying to create a structure to interface with the GSL Monte-Carlo algorithms (a fact that is really not important for this example). I have searched all of the C++ tutorials, the stackoverflow posts and the GSL documentation with no luck. I am using the armadillo package for matrix manipulation; it is very robust. I am unable to use a dynamic array within the structure, as per the documentation, so I am trying to find a way to make my structure variable *M point to the values in my array *L[]. I am sure that this would be better with a vector but 1) the rest of the code (in bad form) uses pointers already, and 2) I am looking at this as a learning experience. I am surprised that the addresses for *M and *L[] are not the same in my code. I am also, less importantly, surprised that my std::cout prints a different number of spaces for each line. The code exits before printing the last std::cout as shown in the output below.
Thanks for your help!
#include "pch.h"
#include "stdio.h"
#include "complex"
#include "new"
#include "armadillo"
using namespace arma;
class Link
{
public:
arma::Mat<cx_double>::fixed<3, 3>* dir[4]; // pointer to directional SU(3) matrices
Link(); // default constructor
};
Link::Link() // default constructor - all directional matrices are the identity
{
for (size_t hcount = 0; hcount < 4; hcount++)
{
dir[hcount] = new arma::Mat<cx_double>::fixed<3, 3>{ fill::eye }; // create directional matrix in direction hcount
}
}
struct Param
{
Link* M;
};
int main()
{
const int size = 10;
Param* Parameters = new Param{ NULL };
Link* L[size];
arma::Mat<cx_double>::fixed<3, 3> One{ fill::eye };
for (size_t hcount = 0; hcount < 10; hcount++)
{
L[hcount] = new Link();
*L[hcount]->dir[1] = *L[hcount]->dir[1] + hcount * One; // Make each array element #1 unique
}
Parameters->M = L[0];
std::cout << "&L = " << &L << std::endl;
std::cout << "&Parameters->M = " << &Parameters->M << std::endl; // surprised that addresses are not the same
std::cout << std::endl;
std::cout << "&L[0] = " << &L[0] << std::endl;
std::cout << "&Parameters->M[0] = " << &Parameters->M[0] << std::endl;
std::cout << std::endl;
std::cout << "&L[5] = " << &L[5] << std::endl;
std::cout << "&Parameters->M[5] = " << &Parameters->M[5] << std::endl;
std::cout << std::endl;
std::cout << "&L[5]->dir[1] = " << &L[5]->dir[1] << std::endl;
std::cout << "&Parameters->M[5].dir[1] = " << &Parameters->M[5].dir[1] << std::endl;
std::cout << std::endl;
std::cout << "*L[5]->dir[1] = " << *L[5]->dir[1] << std::endl; // This works
std::cout << "*Parameters->M[5].dir[1] = " << *Parameters->M[5].dir[1] << std::endl; // This does not
std::cout << std::endl;
}
OUTPUT
&L = 0024F7CC
&Parameters->M = 004EEFD8
&L[0] = 0024F7CC
&Parameters->M[0] = 004E0578
&L[5] = 0024F7E0
&Parameters->M[5] = 004E05C8
&L[5]->dir[1] = 004E50C4
&Parameters->M[5].dir[1] = 004E05CC
*L[5]->dir[1] = (+6.000e+00,+0.000e+00) (0,0) (0,0)
(0,0) (+6.000e+00,+0.000e+00) (0,0)
(0,0) (0,0) (+6.000e+00,+0.000e+00)
*Parameters->M[5].dir[1] =
&L is the adress of L, so it's the adress of the pointer to the first element not the adress of the first elemenr itself. Same for & Parameters->M. That is the adress of thd the Member M from Parameters. You want to compare L[0] with Parameters->M except when M should not point to the element that L[0] refers to but to the start of the array itself, then you want to compare it with L. But then you also have to change the assignment.
I find it a bit weird that you use an array of pointers. Just use an array of Links.

How set value in constant into struct c++

I can not assign a value to a constant within a structure, follow the code:
#include <iostream>
#include <stdio.h>
typedef struct
{
float a;
float b;
float c;
float intensity;
} PointXYZI;
typedef struct structParent{
int x;
int y;
const PointXYZI* xyzi;
} structParent;
int main()
{
float o = 10.f, p = 5.0f, z = 96.0f;
PointXYZI points = {o, p, z};
const structParent *data = {0,0, &points};
std::cout << " *-* " << data.xyzi->c << std::endl;
std::cout << " *-* " << points.a << std::endl;
return 0;
}
I get the following error with this code:
error: scalar object ‘data’ requires one element in initializer const structParent *data = {0,0, &points};
Thank you...
An explained by example version of #UnholySheep's answer is the following.
void someFunc(const structParent &x)
// ^^^^^^
{
std::cout << " #_# " << x.xyzi->c << std::endl;
}
int main()
{
float o = 10.f, p = 5.0f, z = 96.0f;
PointXYZI points = {o, p, z, 0};
// ^^^^^
const structParent data = {0,0, &points};
// ^^^
std::cout << " *-* " << data.xyzi->c << std::endl;
std::cout << " *-* " << points.a << std::endl;
someFunc(data);
// ^^^^^^^
return 0;
}

How can I build a proper constructor and destructor?

Question #1: How can I build a constructor set the value for (R,PoF,PoR)? I am trying to understand how constructor works but I guess I don't quite get it.
Question #2: Can I build destructor in this way, instead of the way I used in my program?
Circle::~Circle()
{
std::cout << "The fence would cost " << SwimmingPool.PerimeterP(r) << std::endl;
std::cout << "The road would cost " << SwimmingPool.AreaP(r) << std::endl;
std::cout << "Present by FF" << std::endl;
}
I just want the cost to come out by itself, but I don't know how should I create destructor to do so.
Here is my full code:
#include "stdafx.h"
#include "iostream"
const double PI = 3.1415926;
class Circle
{
public:
Circle();
double AreaP(int r);
double PerimeterP(int r);
~Circle();
private:
int R;
int PoF;
int PoR;
};
double Circle::AreaP(int r)
{
return ((r + R)*(r + R) - r*r)*PI*PoR;
}
double Circle::PerimeterP(int r)
{
return (r + R) * 2 * PI*PoF;
}
Circle::Circle()
{
int R = 3;
int PoF = 35;
int PoR = 20;
}
Circle::~Circle()
{
std::cout << "Present by FF" << std::endl;
}
int main()
{
int r;
Circle SwimmingPool;
std::cout << "Please input the radius of the Swimming Pool." << std::endl;
std::cin >> r;
std::cout << "The fence would cost " << SwimmingPool.PerimeterP(r) << std::endl;
std::cout << "The road would cost " << SwimmingPool.AreaP(r) << std::endl;
return 0;
}
You have:
Circle::Circle()
{
int R = 3;
int PoF = 35;
int PoR = 20;
}
That function creates three function local variables and sets their values. It does not initialize the members of the class. Change it to:
Circle::Circle() : R(30), PoF(35), PoR(20) {}
Always prefer to initialize in the initializer list instead of setting the values in the body of the constructor.
No, you may not use:
Circle::~Circle()
{
std::cout << "The fence would cost " << SwimmingPool.PerimeterP(r) << std::endl;
std::cout << "The road would cost " << SwimmingPool.AreaP(r) << std::endl;
std::cout << "Present by FF" << std::endl;
}
SwimmingPool is a variable in main. It cannot be used in the destructor. Besides, it does not make sense to print those messages in the destructor. It should simply be
Circle::~Circle()
{
}
Circle::Circle() : R(3), PoF(3), PoR(3) {};
Define the R, PoF, PoR as const int
The destructor must not throw an exception and generally you want it to release resources acquired by the object. Usually not the best place to be outputting stuff to stdout.
Don't use std::endl unless you want to flush the stream. Use '\n' instead.

C++ Cycle through the addresses of an object

Objects (that are not dynamic) are blocks of data in memory.
Is there a way to cycle through and print each item in an object?
I tried doing it with 'this' but I keep getting errors.
#include "stdafx.h"
#include <iostream>
#include "TestProject.h"
using namespace std;
class myclass {
int someint = 10;
double somedouble = 80000;
int somearray[5] = {0, 1, 2, 3, 4};
public:
void somefunction();
};
void myclass::somefunction() {
cout << "\n test \n" << this;
myclass *somepointer;
somepointer = this;
somepointer += 1;
cout << "\n test2 \n" << *somepointer;
//Error: no opperator '<<' matches these operands
}
int main() {
myclass myobject;
myobject.somefunction();
return 0;
}
I'm guessing the error is because the types don't match. But I can't really figure a solution. Is there a dynamic type, or do I have to test the type somehow?
You must add friend global std::ostream operator << to display content of object
#include "stdafx.h"
#include <iostream>
using namespace std;
class myclass {
int someint;
double somedouble;
int somearray[5];
public:
myclass()
{
someint = 10;
somedouble = 80000;
somearray[0] = 0;
somearray[1] = 1;
somearray[2] = 2;
somearray[3] = 3;
somearray[4] = 4;
}
void somefunction();
friend std::ostream& operator << (std::ostream& lhs, const myclass& rhs);
};
std::ostream& operator << (std::ostream& lhs, const myclass& rhs)
{
lhs << "someint: " << rhs.someint << std::endl
<< "somedouble: " << rhs.somedouble << std::endl
<< "somearray: { ";
for (int iIndex = 0; iIndex < 5; iIndex++)
{
if (iIndex == 4)
lhs << rhs.somearray[iIndex] << " }" << std::endl;
else
lhs << rhs.somearray[iIndex] << ", ";
}
return lhs;
}
void myclass::somefunction() {
cout << "\n test \n" << this;
myclass *somepointer;
somepointer = this;
somepointer += 1; // wrong pointer to object with `object + sizeof(object)` address,
// data probably has been corrupted
cout << "\n test2 \n" << *somepointer; // displaying objects content
}
int main() {
myclass myobject;
myobject.somefunction();
return 0;
}
as you want to get to the object member using its pointers shifts I post another program
#include "stdafx.h"
#include <iostream>
using namespace std;
#pragma pack (push, 1) // force data alignment to 1 byte
class myclass {
int someint;
double somedouble;
int somearray[5];
public:
myclass()
{
someint = 10;
somedouble = 80000;
somearray[0] = 0;
somearray[1] = 1;
somearray[2] = 2;
somearray[3] = 3;
somearray[4] = 4;
}
void somefunction();
friend std::ostream& operator << (std::ostream& lhs, const myclass& rhs);
};
#pragma pack (pop) // restore data alignment
std::ostream& operator << (std::ostream& lhs, const myclass& rhs)
{
lhs << "someint: " << rhs.someint << std::endl
<< "somedouble: " << rhs.somedouble << std::endl
<< "somearray: { ";
for (int iIndex = 0; iIndex < 5; iIndex++)
{
if (iIndex == 4)
lhs << rhs.somearray[iIndex] << " }" << std::endl;
else
lhs << rhs.somearray[iIndex] << ", ";
}
return lhs;
}
void myclass::somefunction() {
int* pSomeInt = (int*)this; // get someint address
double *pSomeDouble = (double*)(pSomeInt + 1); // get somedouble address
int* pSomeArray = (int*)(pSomeDouble + 1); // get somearray address
std::cout << "someint: " << *pSomeInt << std::endl
<< "somedouble: " << *pSomeDouble << std::endl
<< "somearray: { ";
for (int iIndex = 0; iIndex < 5; iIndex++)
{
if (iIndex == 4)
std::cout << pSomeArray[iIndex] << " }" << std::endl;
else
std::cout << pSomeArray[iIndex] << ", ";
}
}
int main() {
myclass myobject;
myobject.somefunction();
return 0;
}
C++, by design, has no reflection feature. This means there is no generic, type-independent way to acces type metadata (e.g. the list of members if a class and their types) at runtime. So what you're trying to do (if I understand it correctly) cannot be done in C++.
Also I'm not sure what you meant by "objects (that are not dynamic)". all objects are blocks of data in memory, regardless of whether they are dynamically allocated or not.

Pointer-to-member: what does the pointer value represent?

I am playing with pointer-to-members and decided to actually print the values of the pointers. The result was not what I expected.
#include <iostream>
struct ManyIntegers {
int a,b,c,d;
};
int main () {
int ManyIntegers::* p;
p = &ManyIntegers::a;
std::cout << "p = &ManyIntegers::a = " << p << std::endl; // prints 1
p = &ManyIntegers::b;
std::cout << "p = &ManyIntegers::b = " << p << std::endl; // prints 1
p = &ManyIntegers::c;
std::cout << "p = &ManyIntegers::c = " << p << std::endl; // prints 1
p = &ManyIntegers::d;
std::cout << "p = &ManyIntegers::d = " << p << std::endl; // prints 1
return 0;
}
Why is the value of p always 1? Shouldn't the value of p somehow reflect which class member it points to?
As everyone has said, ostream doesn't have the appropriate operator<< defined.
Try this:
#include <cstddef>
#include <iostream>
struct Dumper {
unsigned char *p;
std::size_t size;
template<class T>
Dumper(const T& t) : p((unsigned char*)&t), size(sizeof t) { }
friend std::ostream& operator<<(std::ostream& os, const Dumper& d) {
for(std::size_t i = 0; i < d.size; i++) {
os << "0x" << std::hex << (unsigned int)d.p[i] << " ";
}
return os;
}
};
#include <iostream>
struct ManyIntegers {
int a,b,c,d;
};
int main () {
int ManyIntegers::* p;
p = &ManyIntegers::a;
std::cout << "p = &ManyIntegers::a = " << Dumper(p) << "\n";
p = &ManyIntegers::b;
std::cout << "p = &ManyIntegers::b = " << Dumper(p) << "\n";
p = &ManyIntegers::c;
std::cout << "p = &ManyIntegers::c = " << Dumper(p) << "\n";
p = &ManyIntegers::d;
std::cout << "p = &ManyIntegers::d = " << Dumper(p) << "\n";
return 0;
}
Standard ostream operator<< has no overload for pointer to member, so you pointer has been implicitly converted to bool.
p actually contains offset in object. Printing them prints implicit converted bool value true or false if they really contains some offset or not respectively. Conversion happens due to the fact that ostream's insertion member doesn't have any overload for pointers to members.
There is no overload of operator<< which takes pointer-to-member as argument. So if you try printing pointer-to-member, it implicitly converts into true which gets passed to the overload which takes bool as argument, and it prints 1 corresponds to true.
If you use std::boolalpha stream-manipulator, it will print true instead of 1:
std::cout << std::boolalpha << "p = &ManyIntegers::a = " << p ;
//^^^^^^^^^^^^^^
Output (see at ideone):
p = &ManyIntegers::a = true
A member pointer isn't necessarily a numeric value, more often than not it will be a struct or something the like. I don't think there is a way to obtain a value from a member pointer, but even if there is I don't see how that would be useful.
Here's a fully standards-compliant implementation to show the in-memory representation of the pointer-to-members:
#include <iostream>
#include <iomanip>
template<int... I> struct index_tuple { using succ = index_tuple<I..., sizeof...(I)>; };
template<int I> struct indexer { using type = typename indexer<I - 1>::type::succ; };
template<> struct indexer<0> { using type = index_tuple<>; };
template<typename T> typename indexer<sizeof(T)>::type index(const T &) { return {}; }
template<typename T> class dumper {
unsigned char buf[sizeof(T)];
friend std::ostream &operator<<(std::ostream &os, const dumper &o) {
std::ios_base::fmtflags flags{os.flags()};
std::copy_n(o.buf, sizeof(T),
std::ostream_iterator<int>(os << std::hex << std::showbase, " "));
return os << std::setiosflags(flags);
}
template<int... I> dumper (const T &t, index_tuple<I...>):
buf{reinterpret_cast<const unsigned char *>(&t)[I]...} {}
public:
dumper(const T &t): dumper(t, index(t)) {}
};
template<typename T> dumper<T> dump(const T &t) { return {t}; }
struct ManyIntegers {
int a,b,c,d;
};
int main () {
std::cout << "p = &ManyIntegers::a = " << dump(&ManyIntegers::a) << std::endl;
std::cout << "p = &ManyIntegers::b = " << dump(&ManyIntegers::b) << std::endl;
std::cout << "p = &ManyIntegers::c = " << dump(&ManyIntegers::c) << std::endl;
std::cout << "p = &ManyIntegers::d = " << dump(&ManyIntegers::d) << std::endl;
}
Output is as expected:
p = &ManyIntegers::a = 0 0 0 0
p = &ManyIntegers::b = 0x4 0 0 0
p = &ManyIntegers::c = 0x8 0 0 0
p = &ManyIntegers::d = 0xc 0 0 0