C++ call method on object with the object itself as parameter - c++

In python you can, for example, call array.sort() and it will sort the array it is called on. However, I now have the following code snippet
void drawClickableRectangle(ClickableRectangle recto){
ofSetHexColor(0xffffff); // just some syntax from the library I'm using
ofFill();
ofDrawRectangle(recto.xpos, recto.ypos, recto.width, recto.height);
}
and then call this method here:
ClickableRectangle recto(1,1,100,100);
recto.drawClickableRectangle(recto);
This is the full class:
class ClickableRectangle
{
// Access specifier
public:
// Data Members
int xpos, ypos, width, height;
ClickableRectangle(int x1, int y1, int width1, int height1){
xpos = x1;
ypos = y1;
width = width1;
height = height1;
};
// Member Functions()
int getxpos()
{
return xpos;
}
int getypos(){
return ypos;
}
int getwidth(){
return width;
}
void drawClickableRectangle(ClickableRectangle recto){
ofSetHexColor(0xffffff);
ofFill();
ofRect(recto.xpos,recto.ypos, recto.width, recto.height);
//ofDrawRectangle(recto.xpos, recto.ypos, recto.width, recto.height);
}
Is there a way to make the function call "reflexive"? So I can just call it like:
recto.drawClickableRectange();
I'm relatively new to C++, but not to programming in general. Thanks!

You can do like this in C++:
class ClickableRectangle {
public int xpos;
public int ypos;
public int width;
public int height;
void drawClickableRectangle(){
ofSetHexColor(0xffffff); // just some syntax from the library I'm using
ofFill();
ofDrawRectangle(xpos, ypos, width, height);
}
}
Then in your main function, call it like this:
int main(){
ClickableRectangle recto;
recto.xpos = 1;
recto.ypos = 1;
recto.width = 100;
recto.height = 100;
recto.drawClickableRectange();
return 0;
}

Not in the same way as python, no.
In python, you can
def unattached(fake_self):
return fake_self.x
class Thing:
def __init__(self):
self.x = 42
Thing.method = unattached
thing = Thing()
print (thing.method())
print (unattached(thing))
Because there's no difference between a free function with an explicit first paramter and a instance method with an implicit first parameter.
In C++, you can't change a class at runtime, and a member function has a different type to a free function.
struct Thing {
int x = 42;
int method() const { return this->x; }
}
int unattached(const Thing * thing) { return thing->x; }
The type of unattached is int (*)(const Thing *), whereas method is a int (const Thing::*)(). These are different types, you can't switch one for the other. You can however construct a std::function<int(const Thing *)> from either of them, but you can only use that with the free function syntax func(thing), as it isn't a member of Thing

Related

Problem passing function pointer to a class c++

I'm trying to implement a numerical ODE solver in c++ but I'm having troubles with function pointers (I'm still trying to understand how they works inside classes).
I have a parent class (ODEint) and subclasses in which I will implement different possible algorithms to solve an equation. I pass a function pointer to the parent class (the function represents the equation which is independent of the solver) but I need that function in the child class (different solvers threat that equation in different ways).
When I call the function via pointer in the child class I get the error
odeint.cpp:38:13: error: ‘((Euler*)this)->Euler::.ODEint::field’ cannot be used
as a member pointer, since it is of type ‘pfunc {aka std::vector ()(double)}’
(this->*field)(y);
Here are classes definitions
typedef vector<double> (*pfunc)(double*);
class ODEint {
protected:
double h;
int neq;
double* init_cond;
int nsteps;
string method;
vector<vector<double>> y;
pfunc field;
public:
ODEint(int neq, int nsteps, pfunc);
void setInitCond(double* init_cond);
void solveEq();
virtual vector<double> advance(double h, double *y);
};
class Euler: public ODEint {
public:
Euler(int neq, int nsteps, pfunc, double h);
vector<double> advance(double h, double *y);
};
And here is part of the classes implementation
ODEint::ODEint(int neq, int nsteps, pfunc field){
this->neq = neq;
this->nsteps = nsteps;
this->y.resize(nsteps);
this->field = field;
for (int i = 0; i < nsteps; i++){
this->y[i].resize(neq);
}
}
Euler::Euler(int neq, int nsteps, pfunc field, double h) : ODEint(neq, nsteps, field){
this->h = h;
}
void ODEint::solveEq(){
int n;
cout << "Strarting solver..." << endl;
vector<double> x;
for (n = 0; n < this->nsteps; n++){
x = y[n];
y[n+1] = this->advance(this->h, &x[0]);
}
cout << "Solution termined. Nsteps: " << n << endl;
}
vector<double> Euler::advance(double h, double *y){
vector<double> ynext; ynext.resize(this->neq);
vector<double> f; f.resize(this->neq);
(this->*field)(y); <---------------------------------------------- here is the problem
for (int i = 0; i < this->neq; i++){
ynext[i] = y[i] + h*f[i];
}
}
Finally here is the main
vector<double> field(double *y){
vector<double> vf;
vf[0] = -y[0];
vf[1] = -y[1];
return vf;
}
int main(){
double init_cond[2] = {1.0, 2.0};
const int neq = 1;
Euler prova(neq, (int)1e4, field, 1e-4);
prova.setInitCond(&init_cond[0]);
prova.solveEq();
return 0;
}
I know there may be other problems but I'm still learning c++ and actually the priority is to understand the reason of this error.
Thank you in advance and sorry if the code is a bit confused but as I said previously I'm a kind of beginner.
Your example is a bit large, I didn't use it as-is. But I can spot a fix, with a smaller repro: (I kept your style)
#include <vector>
typedef std::vector<double> (*pfunc)(double*);
class Foo
{
public:
pfunc field;
};
std::vector<double> Bar(double*)
{
return std::vector<double>{};
}
int main()
{
Foo f;
double x;
f.field = &Bar;
(&f)->field(&x);
}
The only meaningful change I needed is to remove the * in front of the call to field().
Now, I will advise not using this pattern at all. The OOP way, IMO would be way cleaner here:
class BaseODE
{
public:
virtual std::vector<double> field(double*) = 0;
// put the rest of the code here.
// when field is called, the Euler version will be called.
};
class Euler:public BaseODE
{
public:
virtual std::vector<double> field(double*) override;
};
Basically, you have no need yet for function pointers, lambdas, std::function or anything complex.

Is it possible to override the default behavior of getting a struct member in C++?

Similar to the #property tag in python, I am trying to figure out if it is possible to override the behavior of a getter in c++ without having to make a function call.
Basically, is it possible to do the following in c++:
class vector2(class):
def __init__(self):
self.values = [1,2]
#property
def x(self):
return self.values[0]
pos = vector2()
my_var = pos.x
Is the best solution to just write getters and setters?
The short answer is no, you can't do that.
For a 2D vector that you can access as an array, I would do something like this:
struct Vec2 {
float x;
float y;
const float &operator[](const size_t i) const {
static_assert(sizeof(Vec2) == 2 * sizeof(float));
assert(i < 2);
return (&x)[i];
}
float &operator[](const size_t i) {
return const_cast<float &>(std::as_const(*this)[i]);
}
};
So you can access the member variables directly or use the overloaded subscript operator.
Vec2 v{4, 5};
v.x += 9;
v[1] = -3;
In general, getters and setters are called explicitly. A naming convention I've seen quite a lot of is giving the getter and setter the same name.
class Foo {
public:
int member() const {
return hidden;
}
void member(const int value) {
hidden = value;
}
private:
int hidden;
};
This naming convention makes access very clean but still makes it clear that a function call is taking place.
Foo f;
f.member(5);
int five = f.member();

Pointer arguments in void function returning inconsistent values

This might be a stupid simple thing I'm overlooking, but I am setting values in the Data::Data(char *DataType...) function as they are being passed in, and as I hover over them, they are setting fine (the variables type, material, ID, unit, reading when hovered over are what they should be).
However, when the getData function is called below, when I hover over the pointer arguments(*type, *materials.. etc) they are set to random strings like directory names and file names. I'm not sure why this is happening, because when the variables are being set above they are right.
I've included the header and implementation files for the Data class, where all of these functions are defined, but If I need include where they are being called please let me know, the only reason I didn't is because the calls are short and files are filled with other irrelevant stuff. Thanks
Data.cpp
#include "Data.hpp"
Sensor::Sensor(char *DataType, char *Material, int ID, char *Sensor, double Min, double Max) {
strcpy(type, Type);
strcpy(material, Material);
ID = SIDs;
strcpy(unit, Units);
max = Maxs;
min = Mins;
}
Sensor::Sensor() {}
double Data::generateData() {
reading = min + (rand() % (int)(max - min + 1));
return reading;
}
void Data::getData(char *type, char *material, int *ID, char *unit, double *reading) {
return;
}
Data::~Data(){}
Data.hpp
#ifndef Data_hpp
#define Data_hpp
#include
#include
#include
using namespace std;
class Data
{
public:
Data();
Data(char *Type, char *Material, int ID, char *Unit, double Min, double Max);
~Data();
void getData(char *type, char *material, int *ID, char *unit, double *reading);
private:
char type[32];
char material[32];
int ID;
int reading;
char unit[32];
double min;
double max;
double generateData();
};
#endif
Your implementation of Sensor::getData does not do what you think it does.
Let's look at this class:
class Foo
{
void getX(int* x)
{
}
int* x;
};
Within getX, the parameter x hides the member x of the same name. This function does literally nothing: A user passes a pointer to an int, which gets the name x in this function. The member is not automatically copied into there (which would be surprising, since you could name the parameter anything else). If you want to do that, you must do it explicitly:
void getX(int* x)
{
*x = *this->x; // Pointed-to value is copied
//x = this->x; // Pointer is copied
}
If you do not set the function parameter to anything, the pointer will keep pointing to random garbage in memory, which is what you are seeing in your debugger.
The more common way to denote "this parameter will be changed/set by this function" is passing a reference:
class Foo
{
void get(char*& x, int*& y, double& z)
{
x = this->x; // Now both parameter and member point to the same location.
y = this->y; // Now both parameter and member point to the same location.
z = this->z;
}
char x[32];
int* y;
double z;
};
Or, if you don't want to copy the pointers but the pointed-to values:
void get(char* x, int* y, double& z)
{
strcopy(x, this->x);
*y = *this->y;
z = this->z;
}
(PS: I recommend using std::string instead of char arrays if your use case allows for it.)
You uninitialized arguments are set to random garbage no matter if you call getData() or not. Try to print them out without calling getData() and see.

Store cursor position in class object (ncurses c++)

I am using QTCreator to compile my c++ code and the <curses.h> library.
Let us say we have the following class definition (.h):
struct coordinateYX
{
int y;
int x;
coordinateYX(long int yPos, long int xPos);
coordinateYX() {}
}
class Rogue
{
private:
long int health;
coordinateYX heroPosition;
public:
long int getHealth();
void setHealth(long int initHealth);
void healthChange(long int vDelta);
coordinateYX getHeroPosition();
void setHeroPosition(coordinateYX hPos);
};
and (.cpp):
coordinateYX::coordinateYX(long int yPos, long int xPos) : y{yPos}, x{xPos} {}
long int Rogue::getHealth() {return health;}
void Rogue::setHealth(long int initHealth) {health = initHealth;}
void Rogue::healthChange(long int vDelta) {health += vDelta;}
coordinateYX Rogue::getHeroPosition() {return heroPosition;}
void Rogue::setHeroPosition(coordinateYX hPos)
{
heroPosition.y = hPos.y;
heroPosition.x = hPos.x;
}
In my main.cpp, I am trying to store the current cursor position into an instantiation of Rogue:
Rogue Hero;
getyx(stdscr, Hero.getHeroPosition().y, Hero.getHeroPosition().x);
But I always get an error:
using temporary as lvalue [-fpermissive]
It also shows this below as part of the error which is in the <curses.h> file
#define getyx(w, y, x) (y = getcury(w), x = getcurx(w))
Although I can simply store these values in another struct initialized in main.cpp, how can I store the x and y positions directly in the class data members?
Thank you.
The quickest solution would be to change getHeroPosition to return a reference instead of value:
coordinateYX& Rogue::getHeroPosition() {return heroPosition;}
The problem is here you are trying to assign to the Rogue position:
getyx(stdscr, Hero.getHeroPosition().y, Hero.getHeroPosition().x);
This is equivalent to:
Hero.getHeroPosition().y = getcury(stdscr);
Hero.getHeroPosition().x = getcurx(stdscr);
But getHeroPosition returns the position by value (it returns a copy, an rvalue). If you assign a value to that temporary copy it will just be lost. The solution is to assign to a reference to the actual Rogue position (an lvalue).
Alternatively, you can use your existing setPosition function:
coordinateYX position;
getyx(stdscr, position.X, position.Y);
Hero.setPosition(position);

Constructor in implementation versus header

The constructor should, to my knowledge, be defined in the implementation file but I've only been able to find examples with the class inside one main file instead of split into a .h and .cpp file
All I need to know is if my following code is separated in an acceptable manner..
Entity.h:
using namespace std;
class cEntity {
private:
/*-----------------------------
----------Init Methods---------
-----------------------------*/
int *X, *Y;
int *Height, *Width;
public:
/*-----------------------------
----------Constructor----------
-----------------------------*/
cEntity (int,int, int, int);
/*-----------------------------
----------Destructor-----------
-----------------------------*/
~cEntity ();
/*-----------------------------
----------Set Methods----------
-----------------------------*/
/*Set X,Y Methods*/
void setX(int x){*X=x;};
void setY(int y){*Y=y;};
void setXY(int x, int y){*X=x; *Y=y;};
/*Set Height, Width Methods*/
void setHeight(int x){*Height=x;};
void setWidth(int x){*Width=x;};
void setDimensions(int x, int y){*Height=x; *Width=y;};
/*-----------------------------
----------Get Methods----------
-----------------------------*/
/*Get X,Y Methods*/
int getX(){return *X;};
int getY(){return *Y;};
/*Get Height, Width Methods*/
int getHeight(){return *Height;};
int getWidth(){return *Width;};
};
and Entity.cpp:
#include "Entity.h"
cEntity::cEntity (int x, int y, int height, int width) {
X,Y,Height,Width = new int;
*X = x;
*Y = y;
*Height = height;
*Width = width;
}
cEntity::~cEntity () {
delete X, Y, Height, Width;
}
I would also like to say thanks to everyone for being so helpful, especially on my first question!
cEntity::cEntity (int x, int y, int height, int width) {
is correct
X,Y,Height,Width = new int;
not so much. That sets Width to a new int, but not the rest. You probably intended:
X = new int(x);
Y = new int(y);
Height = new int(height);
Width = new int(width);
Note that this method of construction will not work for objects without assignment/copy, like references. For some objects, it's also slower than constructing them in place. As such, the preferred way to construct is like so:
cEntity::cEntity (int x, int y, int height, int width) {
:X(new int(x))
,Y(new int(y))
,Height(new int(height))
,Width(new int(width))
{}
This is better, but if any exceptions are thrown, you'll have to somehow deallocate the ones that were allocated. Better is to make each of those members a std::unique_ptr<int>, so they'll deallocate themselves and save you many headaches.
Yes, it's OK.
However, there is a problem with your constructor and destructor.
What your code actually does is allocating one int and your destructor deallocates one int also.
Anyway, there is no need to use pointers here.
Somewhat better implementation (if we don't use smart pointers), could be:
[Entity.h]
private:
/*Private fields*/
int X, Y;
int Height, Width;
[Entity.cpp]
cEntity::cEntity (int x, int y, int height, int width) {
X = x;
Y = y;
Height = height;
Width = width;
}
cEntity::~cEntity () {
}
And one more thing. Try to avoid using namespace std; in your header files. If you do, you force those who include your header to use this using statement and it can provoke namespace clashes.
Your separation is fine. The implementations of those functions is wrong, but you've separated them from the declaration suitably. (They don't allocate or free as many objects as you think they do.)
Yes. For the separation at least, that's generally the best way to do it.
As for the actual implementation you have some issues. I am not really sure what you are trying to do with the constructor or if you have the correct data types for the class member variables but something seems off.
Any method defined in the class directly is implicitly inlined, including the constructor.
I.e.
class MyClass
{
public:
MyClass() {};
};
defines an inline constructor, which may (or may not) improve your code performance,
Whereas
class MyClass
{
public:
MyClass();
};
MyClass::MyClass()
{
};
is not inlined, and therefore won't have those benefits. Both options are correct C++ though.
Just my 2 cents.
P.S And yes, when you decide to store pointers inside a class in this manner, you open a Pandora box.