I have a struct Creature and a struct Game. Game is a "friend" of Creature.
In game I have
vector creatures;
and I add a creature x to that vector thourgh a function called addC
void addc (Creature& c){
creatures.push_back(c);
}
Now I'm in another function "foo" that is a public method of the struct Game.
void foo (Creature& c){
...
}
In that function I need to find another creature from the vector creatures that
matches some information from Creature c.
So I made another public method in Game called fooHelper
void fooHelper (char s, int x, int y){
bool found = false;
for (int i = 0; i < creatures.size() && (!found); ++i){
Creature& c = creatures[i];
if (x == c.x && y == c.y){
c.s = s;
found = true;
}
}
}
however when I check if the second creature's "s" member is being updated, it turns out that
it is not! I don't understand what I'm doing wrong since I'm pushing by references to the vector.
and I'm getting the creature by reference from the vector.
the vector in game looks like this
struct Game{
private:
vector<Creature> creatures;
...
}
struct Creature{
private:
char s;
int x; int y;
...
}
any help would be much appreciated!
This statement:
creatures.push_back(c);
Stores a copy of c into your vector: standard containers have value semantics. If you need reference semantics, you should store pointers into your vector.
Usually it is a good idea to use smart pointers, and which one to use depends on the ownership policy of your application. In this case, based on the information I could get from your question's text, it seems reasonable to let Game be the unique owner of all Creatures in the game (and therefore the only object which is responsible for the lifetime of the owned Creatures, and in particular for destroying them when they won't be needed anymore), so std::unique_ptr should be a good choice:
#include <memory> // For std::unique_ptr
struct Game{
private:
std::vector<std::unique_ptr<Creature>> creatures;
...
};
Your member function addc() would then become:
void addc(std::unique_ptr<Creature> c)
{
creatures.push_back(std::move(c));
}
And a client would invoke it this way:
Game g;
// ...
std::unique_ptr<Creature> c(new Creature());
g.addc(std::move(c));
Your foohelper() function, on the other hand, would be rewritten into something like this:
void fooHelper (char s, int x, int y) {
bool found = false;
for (int i = 0; i < creatures.size() && (!found); ++i){
std::unique_ptr<Creature>& c = creatures[i];
if (x == c->x && y == c->y) {
c->s = s;
found = true;
}
}
}
Finally, your class Game could return non-owning raw pointers (or references) to clients requiring access to the stored creatures.
When you push your creature reference into the vector, it's making a copy. It's a vector of type "Creature", and so it's making a copy from the reference that you give it. One solution would be to keep a vector of creature pointers.
edit - this question helps explain things a little better than I was able to on why you can't have a vector of references: Why can't I make a vector of references?
Related
so I have a struct bullet:
struct Bullet {
int posX; int posY;
int verticalBulLimiter = 0;
int verticalBulLimiterCheck = 35; // aka movement Speed
void draw() {
gotoxy(posX,posY);
setColor(14);
cout << bullet << endl;
if (posY - 1 == 0){
/// I want to delete struct here
}
if (verticalBulLimiter == verticalBulLimiterCheck) {
posY--;
clearPixel(posX, posY + 1);
verticalBulLimiter = 0;
}
else {
verticalBulLimiter++;
}
}
};
as You can see I want to delete the struct once it's variable posY reaches certain value.
So how do I do that. Do I tried using keyword "this" but I dont really know how does it work. Is there any function for 'self destruction' ?
While this can be possible using delete this, it is most definitely not what you want.
Objects in C++ do not usually own themselves, so you should have the owner of the bullet (maybe a scene or world entity) delete it.
Instead of trying to "destroy a struct from within", you should be checking and removing instances of struct that have met some conditions.
There's an algorithm that does just that, like so.
#include <vector>
struct Bullet { ... };
std::vector<Bullet> bullets;
void clean_bullets(){
bullets.erase(
std::remove_if(bullets.begin(), bullets.end(),
[](const Bullet& i){return /* your condition when a bullet should be removed */}),
v.end()
);
}
int main(){
// Add some bullets
bulltes.push_back({/* create a bullet here */});
.
.
.
clean_bullets();
}
The std::vector<Bullet> bullets contains all the bullets, and is responsible for memory, removing, adding elements etc.
You can read more about std::vector here: https://en.cppreference.com/w/cpp/container/vector
And about removing the elements like above, it's called the remove/erase idiom https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Erase-Remove
I have 1 question because I am pretty curious how to handle with such problem.
I have base class called "Pracownik" (Worker) and 2 subclasses which are made from public Pracownik;
- Informatyk (Informatic)
- Księgowy (Accountant)
Writing classes is easy. Made them pretty fast but I have small problem with main because I am helping friend with program but I was not using C++ for a while. So:
This is my header file "funkcje.h"
#include <iostream>
using namespace std;
class Pracownik
{
private:
string nazwisko;
int pensja;
public:
Pracownik(string="",int=0);
~Pracownik();
string getNazwisko();
int getPensja();
friend double srednia_pensja(int,Pracownik);
};
class Informatyk : public Pracownik
{
private:
string certyfikat_Cisco;
string certyfikat_Microsoft;
public:
Informatyk(string="",int=0, string="", string="");
~Informatyk();
void info();
};
class Ksiegowy : public Pracownik
{
private:
bool audytor;
public:
Ksiegowy(string="",int=0, bool=false);
~Ksiegowy();
void info();
};
double srednia_pensja(int,Pracownik);
These are definitions of my functions "funkcje.cpp"
#include "funkcje.h"
Pracownik::Pracownik(string a,int b)
{
nazwisko=a;
pensja=b;
}
Pracownik::~Pracownik()
{
}
string Pracownik::getNazwisko()
{
return nazwisko;
}
int Pracownik::getPensja()
{
return pensja;
}
Informatyk::Informatyk(string a, int b, string c, string d) : Pracownik(a,b)
{
certyfikat_Cisco=c;
certyfikat_Microsoft=d;
}
Informatyk::~Informatyk()
{
}
Ksiegowy::Ksiegowy(string a, int b, bool c) : Pracownik(a,b)
{
audytor=c;
}
Ksiegowy::~Ksiegowy()
{
}
void Informatyk::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Certyfikat Cisco: "<<certyfikat_Cisco<<endl;
cout<<"Certyfikat Microsoft: "<<certyfikat_Microsoft<<endl;
}
void Ksiegowy::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Audytor: ";
if(audytor)
cout<<"Tak"<<endl;
else
cout<<"Nie"<<endl;
}
double srednia_pensja(int a,Pracownik *b)
{
return 0;
}
And finally main!
#include <iostream>
#include "funkcje.h"
using namespace std;
int main()
{
Pracownik lista[10];
Pracownik *lista_wsk = new Pracownik[10];
Informatyk a("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk b("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk c("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy d("Kowalski4",4000,1);
Ksiegowy e("Kowalski5",5000,0);
lista[0]=a;
lista[1]=b;
lista[2]=c;
lista[3]=d;
lista[4]=e;
Informatyk *ab = new Informatyk("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk *ac = new Informatyk("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk *ad = new Informatyk("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy *ae = new Ksiegowy("Kowalski4",3000,1);
Ksiegowy *af = new Ksiegowy("Kowalski5",3000,0);
lista_wsk[0]=*ab;
lista_wsk[1]=*ac;
lista_wsk[2]=*ad;
lista_wsk[3]=*ae;
lista_wsk[4]=*af;
for(int i;i<5;i++)
{
lista[i].info();
cout<<endl;
}
cout<<endl;
// for(int i;i<5;i++)
// {
// lista_wsk[i].info();
// }
return 0;
}
Ok and here goes my questions:
I had to create array which is filled with base class objects "Pracownik".
Secondary i had to create array which is full of pointers to class "Pracownik" objects.
(Hope those 2 first steps are done correctly)
Next thing I had to write to array 3 objects of class Informatic and 2 of class Accountant.
So I ve created 5 objects manually and added them into the array in such way array[0]=a;. I guess this is still good.
Next thing i had to create and add similar objects to array of pointers using new. So I ve created array with new and pointers to objects with new. (Hope thats correct 2).
And FINALLY:
I had to use info() on added to array objects.
This is my main question if my array is type "Pracownik" and I want to use function info() from subclasses how should I do that? And how compiler will know if he should use info() from Accountant or Informatic while I am trying to show those information using "for".
In an array of Pracownik, the elements are of type Pracownik. Any information about the objects being of a subclass of Pracownik are lost when you copy the elements into the array.
This is called object slicing and leads to the fact that there is no way to invoke Informatyk::info() on these objects.
If you want to call methods of a subclass, you have to prevent object slicing by storing pointers or references in the array.
As Oswald says in his answer,
Pracownik * lista_wsk = new Pracownik[10];
allocates an array of 10 Pracownik objects. This is probably not what you want. With polymorphism involved, we usually want to deal with pointers or references. Hence, you'd want an array of Pracownik * pointers. Since you already know at compile-time that it will have 10 members, there is no need for a dynamic allocation here. I think you've meant to write
Pracownik * lista_wsk[10];
instead. Now we don't put objects but pointers to objects into the array. For example:
lista_wsk[2] = new Informatyk("Kowalski3", 3000, "Cisco3", "Microsoft3");
And then we can iterate over the items like so:
for (unsigned i = 0; i < 10; ++i)
std::cout << lista_wsk[i]->getNazwisko() << std::endl;
As you have already discovered, it is impossible to call a subclass function member on a superclass object. It would be possible to figure out the actual type at run-time yourslf by means of a cast.
for (unsigned i = 0; i < 10; ++i)
if (Informatyk * info_ptr = dynamic_cast<Informatyk *>(lista_wsk[i]))
info_ptr->info();
dynamic_cast returns a pointer to the target class if this is possible or a nullptr (which evaluates to false, hence the conditional) otherwise. Note however that this is considered very poor style. It is better to use virtual functions. Therefore, add
virtual void
info()
{
// Do what is appropriate to do for a plain Pracownik.
// Maybe leave this function empty.
}
to the superclass and again to the subclass
virtual void
info() // override
{
// Do what is appropriate to do for an Informatyk.
}
The function in the subclass with the same signature is said to override the function inherited from the superclass. Since the function is marked as virtual, the compiler will generate additional code to figure out at run-time what version of the function to call.
If you are coding C++11, you can make the override explicit by placing the keyword override after its type as shown above (uncomment the override). I recommend you use this to avoid bugs that arise from accidental misspelling or other typos.
I have two classes, in the example added Rectangle and Rectangles. The goal is to make one Rectangles object which holds references to multiple Rectangle objects.
If I change r by r.set_values(4,4) then off coarse r.area() is changed. However if I call rectangles.rects[0].area() it remains 12, and therefore is not changed.
As I understood I am making a reference of r in rectangles, however this seems to be wrong.
How to achieve this?
The code is available here
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
};
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
class Rectangles {
public:
Rectangles(int n);
void addRectangle(Rectangle* r);
Rectangle* rects;
int nRects;
};
Rectangles::Rectangles(int n) {
rects = new Rectangle[n];
nRects = 0;
}
void Rectangles::addRectangle(Rectangle* r) {
rects[nRects] = *r;
nRects++;
}
int main() {
Rectangle r;
Rectangles rectangles(5);
r.set_values(4,3);
rectangles.addRectangle(&r);
cout<<"r.area() before change:"<<r.area()<<endl;
cout<<"rectangles.rects[0].area() before change:"<<rectangles.rects[0].area()<<endl;
r.set_values(4,4);
cout<<"r.area() after change:"<<r.area()<<endl;
cout<<"rectangles.rects[0].area() after change:"<<rectangles.rects[0].area()<<endl;
return 0;
}
Output:
r.area() before change:12
rectangles.rects[0].area() before change:12
r.area() after change:16
rectangles.rects[0].area() after change:12
What is wrong with your code is your definition of Rectangles. It stores a pointer (or an array) to a Rectangle. What you want here is not an array of Rectangle's, but an array of references to Rectangle's. Here, the references shall be pointers, so you need to change this accordingly :
class Rectangles {
public:
Rectangles(int n);
void addRectangle(Rectangle* r);
// Rectangle* rects;
// What you really want :
Rectangle** rects;
int nRects;
};
But then you also need to change the implementation :
Rectangles::Rectangles(int n) {
rects = new Rectangle*[n]; // Array of pointers
nRects = 0;
}
void Rectangles::addRectangle(Rectangle* r) {
rects[nRects] = r; // r is a pointer : just store it, no dereferencing
nRects++;
}
However, this is a bad design : you should not have to use any of these : pointer to pointer (or 'raw array' of pointers), new, and a class whose only purpose is to store an array of things. This is because you already have better tools for this : smart pointers (although you do not need them here either), arrays and dynamic arrays (or vectors).
So, if I were you, this is how I would rewrite your code :
#include <iostream>
#include <vector>
class Rectangle {
public:
void setSize(int w, int h);
int area();
private:
int width, height;
};
void Rectangle::setSize(int w, int h) {
width = w;
height = h;
}
int Rectangle::area() {
return width * height;
}
int main() {
Rectangle r;
std::vector<Rectangle*> rectangles;
r.setSize(4, 3);
rectangles.push_back(&r);
std::cout << "r.area() before change : " << r.area() << std::endl
<< "rectangles[0]->area() before change : "
<< rectangles[0]->area() << std::endl;
r.setSize(4, 4);
std::cout << "r.area() after change : " << r.area() << std::endl
<< "rectangles.rects[0]->area() after change : "
<< rectangles[0]->area() << std::endl;
return 0;
}
Edit :
You might wonder why I used a raw pointer instead of a smart pointer (since I told you to avoid pointers to pointer). This is quite simple : no smart pointer would fit the matter. Let us see why.
std::unique_ptr keeps sole ownership of the object. What if you want another reference to it ? Also, if you ever destroy this smart pointer via std::vector's erase, it would also destroy your object. So if you access it afterwards, you would get some dirty error.
std::shared_ptr keeps shared ownership of the object. Sure, you can have another reference to your object, but the same thing happens if you destroy the pointer. Also, it has some overhead, and is not so easy to use correctly.
std::weak_ptr works with std::shared_ptr, nothing more to say.
A raw pointer, on the contrary, only needs you to ensure that the lifetime of the object is longer or equal to its own lifetime, so that you can always access your object via the pointer. And that is all.
Finally, here is a general rule of thumbs (that I use) :
unique_ptrs are for sole ownership
raw pointers mean whoever gave me the raw pointer guarantees the lifetime of that object to match or exceed my lifetime.
shared_ptrs are for shared ownership
weak_ptrs are for when a system wants to check if the object still exists before using it. This is rare in my code since I find it cleaner to have a system guarantee the lifetime of anything it passes it's subsystems (in which case I use a raw pointer)
class Rectangles {
public:
void addRectangle(Rectangle* r);
vector<Rectangle *> rects;
};
void Rectangles::addRectangle(Rectangle* r) {
rects.push_back(r);
}
int main() {
Rectangle r;
Rectangles rectangles;
r.set_values(4,3);
rectangles.addRectangle(&r);
cout<<"r.area() before change:"<<r.area()<<endl;
cout<<"rectangles.rects[0]->area() before change:"<<rectangles.rects[0]->area()<<endl;
r.set_values(4,4);
cout<<"r.area() after change:"<<r.area()<<endl;
cout<<"rectangles.rects[0]->area() after change:"<<rectangles.rects[0]->area()<<endl;
return 0;
}
Output:
r.area() before change:12
rectangles.rects[0]->area() before change:12
r.area() after change:16
rectangles.rects[0]->area() after change:16
I'm trying to make a chess program, but I want to be able to implement different AIs in it. Thus I made a abstract AIgeneric class and the derived class AIrandom off of AIgeneric. Then in my chessAI interface, I create a list of the the AIs, and try to call their getNextMove function and run into a segfault. The code is as below:
class AIgeneric {
public:
virtual int getNextMove(int*, const int &) = 0;
}
class AIrandom : public AIgeneric {
public:
AIrandom();
virtual int getNextMove(int*, const int &);
}
class chessAI {
public:
chessAI();
~chessAI();
void setAI();
int getNextMove(int*, const int &);
private:
vector<AIgeneric*> AIlist;
vector<string> names;
int selectedAI;
};
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
int chessAI::getNextMove(int * board, const int & color) {
return AIlist[selectedAI]->getNextMove(board, color); //segfault on this line
}
It'd be great if anyone could help me on this problem!
Edit: I do set selectedAI to 0 before calling getNextMove.
In this code:
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
You store a pointer to a local variable into your vector. After the constructor returns that pointer is no longer valid.
Remember that all local variables are stored on the stack, and the stack is reused in other functions. So when you use the pointer in the vector, it now points to some other functions memory and not the one object you declared.
This can be solved in three ways:
Allocate the object on the heap:
AIlist.push_back(new AIRandom);
Not using pointers at all.
Use smart pointers, such as std::unique_ptr.
You call selectedAI = -1; and then AIlist[selectedAI]->.... What do you expect AIlist[-1] to be, other than undefined behavior?
I expect this is because AIlist[selectedAI] is out of bounds. You can confirm this by replacing it with AIlist.at(selectedAI). Keep in mind that this index is -1 immediately after the constructor...
I have a relatively simple question but I cant seem to find an answer specific for my case and I just may not be approaching this problem the right way. I have a class that looks like this:
struct tileProperties
{
int x;
int y;
};
class LoadMap
{
private:
ALLEGRO_BITMAP *mapToLoad[10][10];
tileProperties *individualMapTile[100];
public:
//Get the struct of tile properties
tileProperties *getMapTiles();
};
I have an implementation that looks like this for the getter function:
tileProperties *LoadMap::getMapTiles()
{
return individualMapTile[0];
}
I have code in the LoadMap class that will assign 100 tile properties for each struct in the array. I want to be able to access this array of structs in my main.cpp file but I just cant seem to find the right syntax or approach. My main.cpp looks like this.
struct TestStruct
{
int x;
int y;
};
int main()
{
LoadMap _loadMap;
TestStruct *_testStruct[100];
//This assignment will not work, is there
//a better way?
_testStruct = _loadMap.getMapTiles();
return 0;
}
I realize that there are many approaches to this, but I'm trying to keep this implementation as private as possible. If someone could please point me in the right direction I would greatly appreciate it. Thank you!
TestStruct *_testStruct;
_testStruct = _loadMap.getMapTiles();
This will get you a pointer to the first element in the array returned. You can then iterate through the other 99.
I would highly recommend using vectors, or another container, and writing getters that don't return pointers to bare arrays like that.
First of all, here, why do we need TestStruct, you can use "tileProperties" structure itself...
And imp thing,
tileProperties *individualMapTile[100]; is array of pointers to the structure.
Hence, individualMapTile will have pointers in it.
You have returned the first pointer, hence you can access the first structure only. What about the others????
tileProperties** LoadMap::getMapTiles()
{
return individualMapTile;
}
int main()
{
LoadMap _loadMap;
tileProperties **_tileProperties;
_tileProperties = _loadMap.getMapTiles();
for (int i=0; i<100;i++)
{
printf("\n%d", (**_tileProperties).x);
_tileProperties;
}
return 0;
}
Use vectors instead of arrays where possible. Also consider an array/vector of TestStruct directly rather than pointers to them. I can't tell if that would be appropriate for you from your code sample.
class LoadMap
{
public:
typedef vector<tileProperties *> MapTileContainer;
LoadMap()
: individualMapTile(100) // size 100
{
// populate vector..
}
//Get the struct of tile properties
const MapTileContainer& getMapTiles() const
{
return individualMapTile;
}
MapTileContainer& getMapTiles()
{
return individualMapTile;
}
private:
MapTileContainer individualMapTile;
};
int main()
{
LoadMap _loadMap;
LoadMap::MapTileContainer& _testStruct = _loadMap.getMapTiles();
}