assign passed object to member object in constructor - c++

for some reason I can´t achieve this.
Line::Line(const Pixel &aStart, const Pixel &aEnd){
start = aStart;
end = aEnd;
}
the Line class:
class Line : public Vertex{
public:
Line(const Pixel &start, const Pixel &end);
Pixel getStart();
Pixel getEnd();
private:
Pixel start;
Pixel end;
};
g++ tells me
error: no matching function for call to ‘Pixel::Pixel()’
note: candidates are:
- Pixel::Pixel(int, int, int, int, int)
- Pixel::Pixel(int, int)
- Pixel::Pixel(const Pixel&)//not implemented by me, some sort of default constructor?
I thought actually Im using the last constructor, but something doesnt work. Any help much appreciated.
EDIT: The Pixel Class:
class Pixel{
public:
Pixel(int x, int y);
Pixel(int red, int green, int blue, int x, int y);
void setRed(int red);
void setGreen(int green);
void setBlue(int blue);
void setColor(int r, int g, int b);
int getRed();
int getGreen();
int getBlue();
bool isChanged();
int getX();
int getY();
private:
int red;
int green;
int blue;
int x;
int y;
bool hasBeenChanged;
};

The Line members of type Pixel, start and end, will be default constructed before the constructor of Line runs and sets them to the objects passed in as arguments. It seems that your Pixel class doesn't have a default constructor (because giving any user-defined constructor will stop the compiler from giving you an implicit default constructor). You need to make use of a constructor member initialization list:
Line::Line(const Pixel &aStart, const Pixel &aEnd)
: start(aStart), end(aEnd)
{ }
This initialises start and end with aStart and aEnd respectively, bypassing the default construction that would normally occur.

Because you declare this
Pixel::Pixel(int, int, int, int, int)
Pixel::Pixel(int, int)
the compiler doesn't generate a default constrcutor, or a constructor exists with arguements having default values.
Pixel start;
Pixel end;
These require a default constructor. It doesn't find one, hence the compiler complains. You current code requires the default constructors.
And as a good practice use the initialization list, which wouldn't ask the arguements to default constructed.
Line::Line(const Pixel &aStart, const Pixel &aEnd):start(aStart), end(aEnd){}

Related

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);

Default Copy Operations for Structs with Constant Members

I have a Texture struct that I am using to hold the width, height, and id number of a texture. I also have a Loader class with many static functions dedicated to loading content, such as textures. The problem arises when I try to declare an uninitialized Texture, and then initialize it later. Here is the code in Texture.h:
namespace bronze {
struct Texture {
const unsigned int id;
const float width;
const float height;
Texture() = default;
Texture(Texture&&) = default;
Texture& operator=(Texture&&) = default;
};
}
In Loader.cpp
Texture(const std::string& file, float scale) {
unsigned int id;
float width, height;
loadTextureUsingExternalLibrary(&id, &width, &height);
doThingsWithTexture(id);
return Texture{id, width, height}
}
And then in main.cpp:
#include "Loader.h"
#include "Texture.h"
using namespace bronze;
Texture tex;
int main() {
tex = Loader::loadTexture("asdf.png", 2.f);
drawTextureOnTheWindowSomehow(tex);
return 0;
}
Here are the (shortened, of course) errors I am getting (MinGW is my compiler):
error: use of deleted function 'bronze::Texture::Texture()'
Texture tex;
note: 'bronze::Texture::Texture()' is implicitly deleted because the default
definition would be ill-formed:
Texture() = default;
...complains about each member being uninitialized
error: use of deleted function 'bronze::Texture& bronze::Texture::operator=
Bronze::Texture&&)'
tex = Loader::loadTexture("asdf.png", 2.f);
note: 'bronze::Texture& bronze::Texture::operator=(bronze::Texture&&)' is
implicitly deleted because the default definition would be ill-formed:
Texture& operator=(Texture&&) = default;
...complains for each struct member that "non-static const member can't use
default assignment operator"
I have been Googling around for a while now, and cannot find anything. Perhaps it is that I do not know what to Google, I do not know. Help is appreciated!
A few parts to this
1.The default constructor doesn't work because you can't have an uninitialized const object (even primitives). For your simple case you probably just want them to be value initialized and this can be achieved easily enough:
struct Texture {
const unsigned int id{};
const float width{};
const float height{};
//...
};
2.You can't use the implicitly generated operator= for an object with const data members because that would require assigning to const objects.
struct A { const int i{}; };
A a1;
A a2(a1); // fine
a1 = a2; // not fine. can't do a1.i = a2.i since a1.i is const!
If you want to be able to assign, you'll need to use non-const data members. You cannot use the implicit operator= if you have const members* You could const_cast but that'd lead to undefined behavior and is a horrible idea (just saying it before someone mentions it in the comments).
You aren't just declaring tex, you are defining it. The point of definition requires being initialized. Trying to assign later is not initializing it.
Don't use global variables.
*unless those const members have an operator=(..) const but that'd be pretty weird
Texture is an aggregate with const members. You must provide the values during initialization.
When you return with return Texture{id, width, height} it does the aggregate initialization for you, but if you try to construct Texture the constructor could never work without initializing the const members.
So you might rather use:
Texture(unsigned int id, float width, float height) : id{id}, width{width}, height{height} {};
Also note that you may not be able to use the implicitly deleted operator=, but you may define your own.
The following program works fine with the assignment operator.
struct Texture {
const unsigned int id;
const float width;
const float height;
int other;
Texture(unsigned int id,float width,float height,int other) : id{id},width{width},height{height},other{other} {};
Texture(const Texture & rhs) : id{rhs.id},width{rhs.width},height{rhs.height} {};
Texture& operator=(const Texture& rhs)
{
other = rhs.other;
return *this;
};
};
int main()
{
Texture t0{1,2,3,0};
auto t1 = Texture(3,3,3,1);
Texture t2 = t0; // t2's constants are initialized to be the same as t0's
t2 = t1; // only the non const member data is copied
return 0;
}

How to workaround "redefinition of default parameter" in class constructor

Consider the following example:
class Rectangle{
Rectangle(int x, int y, int width, int height);
Rectangle(int topLeft_x, int topLeft_y, int bottomRight_x, int bottomRight_y);
};
A Rectangle object may be built giving (x,y) coordinates plus width and height or giving top left points pair and bottom right points pair.
While this is correct from an object oriented point of view, this is not from a compiler point of view, returning the error "member function already defined or declared"
While I normally fix this condition easily in case of member function, simply changing the name according to what it does, this is not possible for constructors.
What is the simpler and correct way to workaround this issue keeping both the way to construct the object?
Another possible solution (other than the pair suggested by #VladfromMoscow) is a static method to perform construction. This lets you give them distinct names, since their argument lists are so similar. Thisi is called the Named Constructor Idiom
class Rectangle
{
public:
static Rectangle createRectangle(int x, int y, int width, int height)
{
return Rectangle(x,y,width,height);
}
static Rectangle createRectangleCorners(int x1, int y1, int x2, int y2)
{
return Rectangle(x1,y1,x2-x1, y2-y1);
}
private:
// Doesn't have to be private, but this forces users to use the above
// constructors
Rectangle(int x, int y, int width, int height);
}
You wrote already yourself
top left points pair and bottom right points pair
So what you need is to define class Point and use this type in the constructor declaration.
Otherwise the constructors are declared like
class Rectangle{
Rectangle(int, int, int, int);
Rectangle(int, int, int, int);
};
As you see these declarations do not make sense even if you will write multiline comments.:)
Another approach is to declare the first constructor like
class Rectangle{
Rectangle(int x, int y, unsigned int width, unsigned int height);
Rectangle(int topLeft_x, int topLeft_y, int bottomRight_x, int bottomRight_y);
};
However this approach is unsafe because each integer literal specified as the third or fourth argument must be casted.
Instead of the class Point you could use standard class std::pair. For example
#include <utility>
//...
class Rectangle{
Rectangle(int x, int y, int width, int height);
Rectangle( const std::pair<int, int> &topLeft, const std::pair<int, int> &bottomRight);
};
Another way on how to solve this problem is by using Tag dispatching:
Instead of using methods with different names, give them a new parameter, e.g.,
struct useCorners {};
struct useDimension {};
class Rectangle
{
Rectangle(useCorners, int topLeft, int topRight, int bottomLeft, int bottomRight)
{ ...
}
Rectangle(useDimension, int topLeft, int topRight, int width, int height)
{ ...
}
};

creating arrays of objects that store arrays attributes

Shape.h
class Shape {
private:
string name;
public:
Shape(name);
string getName();
void setName(string);
};
Triangle.h
class Triangle: public Shape {
private:
int x;
int y;
public:
Triangle(name,int[3],int[3]);
int getX();
int getY();
void setX(int);
void setY(int);
};
Triangle.cpp
Triangle::Triangle(string name,int _x[],int_y[]):Shape(name) {
x[] = _x[];
y[] = _y[];
}
int Square::getX() {
return x
}
int Square::getY() {
return y;
}
void Square::setX(int _x) {
x = _x;
}
void Square::setY(int _y) {
y = _y;
}
i need to create triangle that takes in name and 3 points of (x,y). when i try to create an array of triangle on the main Triangle Tri[50]; i got the following errors
Triangle::Triangle(std::string,int*,int*)
candidates expects 3 arguments, 0 provided
Triangle::Triangle(const Triangle&)
candidates expects 1 argument, 0 provided
can pls help me check what is wrong with my constructor?? is it because i am creating an array of objects that store arrays of x and y? so i need to use references and pointers for it?
When you create
Triangle Tri[50];
it will try to call the default constructor to initialize those elements in your Tri array, however, you did not provide such a default constructor and you did not call the constructor with 3 parameters, therefore, compiler complains.
Meanwhile, you seems to try to directly initialize one array with another inside the constructor of Triangle:
Triangle::Triangle(string name,int _x[],int_y[]):Shape(name) {
x[] = _x[];//^^I don't understand how this will work in practice.
y[] = _y[];
}
There is no direct assignment on arrays in C++, though C++ std::array (since C++11) has overloaded operator=, but this is not true for regular array.

Constructor w/Multiple Arguments in Constructor list not working C++

I'm trying to compile class A, which has a member of class B, where class B has no default constructor and its only constructor requires multiple arguments. Simple, right? Apparently not...
Class A:
class SessionMediator
{
public:
SessionMediator()
: map_(16,100,100)
{}
Tilemap map_, background_, foreground_;
};
Class B:
struct Tile2D;
class Tilemap
{
public:
Tilemap(const unsigned int tile_size, const unsigned int width,
const unsigned int height)
: tiles_(NULL), tile_size_(tile_size)
{
Resize(width, height);
}
inline void Resize(const unsigned int width, const unsigned int height)
{ /* Allocate tiles & assign to width_, height_... */ }
unsigned int tile_size_, width_, height_;
Tile2D* tiles_;
};
I am instantiating SessionMediator like so:
int main(int argc, char** argv)
{
SessionMediator session;
return 0;
}
This is the error I am getting. I'm compiling in XCode on Mac OS 10.5.8 and the compiler is g++:
session_mediator.h: In constructor 'SessionMediator::SessionMediator()':
session_mediator.h:19: error: no matching function for call to 'Tilemap::Tilemap()'
tilemap.h:31: note: candidates are: Tilemap::Tilemap(unsigned int, unsigned int, unsigned int)
tilemap.h:26: note: Tilemap::Tilemap(const Tilemap&)
session_mediator.h:19: error: no matching function for call to 'Tilemap::Tilemap()'
tilemap.h:31: note: candidates are: Tilemap::Tilemap(unsigned int, unsigned int, unsigned int)
tilemap.h:26: note: Tilemap::Tilemap(const Tilemap&)
(Duplicate of above here)
Build failed (2 errors)
I wrote a short compilable example doing basically the same thing, to try to figure out what exactly I was doing wrong, which compiles just fine with no errors in g++:
class A
{
public:
A(int x, int y, int z)
: x_(x), y_(y), z_(z)
{}
int x_, y_, z_;
};
class B
{
public:
B()
: m_a(1,2,3)
{}
A m_a;
};
int main(int argc, char **argv)
{
B test;
return 0;
}
Why does it fail in the first example? The 3 arg constructor for Tilemap (in Ex#1) is being called in the same way that the 3 arg constructor for A is being called (in Ex#2).
The code seems pretty much identical to me in the two examples.
As I was trying to simplify my example a bit, I accidentally left out two important things: other data members in the SessionMediator class.
The problem was that I had two additional members of the Tilemap class ("background_" and "foreground_"), which weren't being initialized in the constructor initialization list like the first member "map_".
The constructor should be changed to this:
SessionMediator()
: map_(16,100,100), background_(1,1,1), foreground_(1,1,1)
{}
I apologize for any time wasted over this question; it turned out to be something much simpler. Hopefully someone else will see this question and realize the mistake they are making.
The only thing I can think of is if you are using the copy constructor:
SessionMediator a = b; or SessionMediator a (b);
You might get in the situation where the default copy constructor of SessionMediator would try to use the default constructor of Tilemap which will cause the error you have.
Try to put map_(16u,100u,100u) in the SessionMediator constructor call to make the constants unsigned. This is the only thing that comes to mind now :-).
This compiles fine for me:
class Tilemap
{
public:
Tilemap(const unsigned int tile_size, const unsigned int width,
const unsigned int height)
{
}
};
class SessionMediator
{
public:
SessionMediator(): map_(16u,100u,100u){}
Tilemap map_;
};
Well, when you do:
Tilemap map_;
You're calling the default ctor - but you don't have one defined, that's the error message.
On the extra:
Tilemap::Tilemap(const Tilemap&)
C++ generates a ctor that takes a reference for you. So the valid matches are (1) the one you defined which takes 3 args and (2) the auto-generated one that takes the const ref.