I have to create a list of objects, so to keep it as smooth as possible I wanted to use std::vector instead of regular array of objects. However I don't exactly know how to use them properly. Here is sample code from my class in which I try to add objects to vecor and in 2nd method to display them.
private:
vector <Student> stud;
public:
void Student::dodaj(){
stud.push_back(Student(getNaz(), getImie(), getLeg(), getRok()));
}
void Student::wypisz(){
cout << "Lista osob:\n";
for (int i = 0; i < 1; i++)
{
cout << endl;
cout << "Nazwisko: " << stud[i].nazwisko << endl;
cout << "Imie: " << stud[i].imie << endl;
cout << "Numer indeksu.: " << stud[i].legitymacja << endl;
cout << "Rok studiow: " << stud[i].rok << endl;
}
And my main:
Student st("Kowalski", "Jan", 123455, 2);
Student test1("Nowak", "Jan", 123, 2);
st.dodaj();
test1.dodaj();
test1.wypisz();
However the output result is only one object for wich I use wypisz(print/display) method, in this case test1, that is displayed instead of two of them - st and test1. Any ideas how to fix that?
It appears that stud is a member of Student, which means that each Student object contains its own vector. When you call dodaj on a particular student, it just adds its own details to the vector it contains.
st.dodaj(); // Adds details of st to st's own vector
test1.dodaj(); // Adds details of test1 to test1's own vector
// Now we have one vector inside st containing a single element
// and one vector inside test1 containing a single element
test1.wypisz(); // Prints elements from test1's vector
Instead, your vector should be outside of your Student class (or at least static). One option would be to do this:
Student st("Kowalski", "Jan", 123455, 2);
Student test1("Nowak", "Jan", 123, 2);
std::vector<Student> stud;
std.push_back(st);
std.push_back(test1);
You may want to have another class (maybe School?) which contains this vector.
Related
I'm trying to code a chess game for usage in terminal. A game consists of a Board class, consisting of Piece classes. For each piece I want to determine the allowed moves if no other pieces where on the board and put this in a vector<pair<int,int>> (a1 = 1,1).
You can image that for a Queen you have more allowed moves than for a pawn. Ideally I would like my Piece to have a variable size vector so it is just filled with moves for that specific Piece.
This is my Piece instantiation:
class Piece{
private:
int row;
int col;
// number of moves made by the piece
int moveCnt;
// white = 1, black = -1
int color;
// 'p', 'n', 'b', 'r', 'q', 'k'
char type;
// permissable moves for the piece
vector<pair<int,int>> permMoves;
// allowable moves for the piece, taking the entire board into account (1. Ke2 is not allowed but permissable)
vector<pair<int,int>> allowedMoves;
and then for the allowed permissable moves I do this:
void Piece::computePermMoveS(){
vector<pair<int,int>> emptyPermMoves {{0,0}};
permMoves.swap(emptyPermMoves);
// PAWN
if (getType() == 'p'){
// add move to one row ahead
pair<int,int> add_pair (getCol(),getRow()+1*getColor());
permMoves.push_back(add_pair);
if (getMoveCnt() == 0){
// add move to two rows ahead
pair<int,int> add_pair (getCol(),getRow()+2*getColor());
permMoves.push_back(add_pair);
}
cout << "new pawn at " << getCol() << ", " << getRow() << endl;
for (int i=0; i<sizeof(permMoves)/sizeof(permMoves[0]); i++){
cout << permMoves[i].first << ", " << permMoves[i].second << endl;
}
}
The last printing statement is for debugging purposes. If I compile and run this, I get that each piece (pawn, rook) has three permissible moves (as a pawn, which is first in the loop has -> 0 0, a3, a4).
Could anyone tell me how to fix this? I tried reserving 21 moves (the most possible) with
Piece(){
permMoves.reserve(21);
allowedMoves.reserve(21);
}
but this is not the solution I want and I don't get this working either. So I would really like to use the original approach of each piece having their unique allowed moves.
for (int i=0; i<sizeof(permMoves)/sizeof(permMoves[0]); i++)
This line is incorrect. The number of entries in a std::vector is given by the size() member function:
for (size_t i=0; i<permMoves.size(); i++){
cout << permMoves[i].first << ", " << permMoves[i].second << endl;
}
What you are doing is assuming that std::vector works the same as an array, but that is not true.
A much easier way to perform the loop is to use a ranged-based for loop instead:
for (auto& p : permMoves)
cout << p.first << ", " << p.second << endl;
I have a long vector of values, a specified user input of row/column size. I need to assign a set of 3 numbers into a vector, from the long list of vectors. The vector with 3 number set will be pushed back into another vector, with user input row/column size. 1 column = the 3 number vector set and so on, until every column is filled out. I have trouble making this code (it needs to be in a loop). Any help please?
The picture is an example of a 4x4 vector, with each column a vector of 3 numbers
It sounds as if you want nested vectors, where each smaller vector inside your "long vector" represents a column of 3 values. If so you could do so like:
std::vector<int> columnVec = { 1, 2, 3 };
std::vector<std::vector<int>> longVector;
longVector.push_back(columnVec);
In the first line we declare a vector representing our column and place three integers inside it. On line two we declare another vector, but this time containing vectors which themselves contain ints, i.e. a vector full of column vectors. We then used push_back() to push the column vector into our vector of vectors. If you needed to print the values you could do so like:
for(auto& vec : longVector) { //Walk through our vector of vectors.
for(int value : vec) { //Walk through our column vectors of values.
std::cout << value; //Print out each value of the column.
}
std::cout << std::endl; //Add a newline.
}
Note that if you print them, the columns will appear as rows in the console. If you care about the formatting in the console it will take a bit more effort and might be worth asking as a separate question.
One possible approach might look something like this:
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
int main()
{
typedef std::vector<int> VecInt;
typedef VecInt::iterator VecIntIter;
typedef std::vector<VecInt> VecVecInt;
typedef VecVecInt::iterator VecVecIntIter;
VecVecInt rows;
const int maxRows = 10, maxCols = 10;
cout << "Values during creation" << endl;
cout << "----------------------" << endl;
for (int rowNum=0; rowNum<maxRows; rowNum++)
{
VecInt curRow;
for (int colNum=0; colNum<maxCols; colNum++)
{
if (colNum != 0)
cout << " ";
int cellValue = rand() % 32;
cout << cellValue;
curRow.push_back( cellValue );
}
cout << endl;
rows.push_back(curRow);
}
cout << endl;
cout << "Values during retrieval" << endl;
cout << "----------------------" << endl;
for (VecVecIntIter rowIter=rows.begin(); rowIter!=rows.end(); rowIter++)
{
VecInt curRow = (*rowIter);
for (VecIntIter colIter=curRow.begin(); colIter!=curRow.end(); colIter++)
{
if (colIter != curRow.begin())
cout << " ";
cout << (*colIter);
}
cout << endl;
}
}
Though, this will store a collection of rows, rather than a collection of columns. Easy enough to change the for loops.
I am having some trouble using two memeber functions on a base class pointer. I have the following code;
cout << "Please input the translation vector. (x value ' ' y value)" << endl;
cin >> Xtrans >> Ytrans;
cout << endl;
new_shape = Trans + user_input; // adds Tranaslated to the key
for(it = shape_map.begin(); it != shape_map.end(); ++it){// loops over map (it is defined earlier)
cout << endl;
if( it->first == user_input){
cout << "ID " << new_shape << " = " << endl; // ouput the key witch also id's the shape
it->second->translate(matrix(Xtrans, Ytrans))->printshape(); //<-this one
}
}
The purpose of the code is to translate a shape (I have different classes for several types that are derived from an abstract base class called polygon) and then print the new shape. I have a translate and a print function that work separately but when I combine them the code runs but crashes when it gets to the marked line.
When I debug the code a line in my translate function is highlighted.
Is this the right way to combine two functions? Should I have some intermediate step?
MORE INFO
shape_map is <string, polygon*>
when I do,it->second->printshape(); or it->second->translate(matrix(Xtrans, Ytrans); it doesn't crash and prints the original shape but I don't know if translate works.
I am trying to calculate the perimeter of a rectangle. first I will prompt the user 4 times for the X and Y cords and store it into a 2D array and pass this 2D array to another class which is method class to proceed with the calculation of the perimeter. But the problem is, I don't know how to pass the 2d array to method class.
I am not asking how to calculate the perimeter, I only need to know how to pass the 2D array from main to method class and get the 2D array at method class.
Please advise.
main.cpp
Method method;
int main() {
int storeXandY[4][2];
for(int i=1;i<5;i++)
{
cout << "Please enter x-ordinate" << i<< endl;
cin>>storeXandY[i][0];
cout << "Please enter y-ordinate" << i << endl;
cin>>storeXandY[i][1];
}
//how to pass the 2D array to method class to do some calculations?
// I was thinking something like passing the 2d array to a consturctor but don't know whether it can be done
method.constructor(storeXandY);
}
method.h
//not sure of what to do
public:
constructor() {
}
method.cpp
//how to get the cords from 2d array from main
Please advise. Thanks
You can do it as :
class Method{
...
public int calcPerimeter(int vals[4][2])
{
// do your calculation here using vals array
}
...
}
From main(), you can simply do :
Method m = new Method();
int perimeter;
m.calcPerimeter(<your_array_name>);
Since you are writing C++, you should try to avoid using C-style arrays. I would do this
Method method;
int main() {
vector<vector<int> > storeXandY(4);
for(int i=0; i!=4; ++i) storeXandY[i].resize(2);
for(int i=1;i<5;i++)
{
cout << "Please enter x-ordinate" << i<< endl;
cin>>storeXandY[i-1][0]; /* you need i-1 here, not i */
cout << "Please enter y-ordinate" << i << endl;
cin>>storeXandY[i-1][1];
}
method.calcPerimeter(storeXandY);
}
where method::calcPerimeter is declared as follows
your_return_type method::calcPerimeter(const vector<vector<int> >& rectangle);
The advantage of using vectors is that you can get the number of elements they hold by invoking their size member function, so that in the above code storeXandY.size() is equal to 4 and storeXandY[0].size() is equal to 2.
this is totally strange. I have some code in which I read some parameters from a file and I store them in two stl vectors. I have atoms and residues, and every atom keeps a pointer to his residue. Once finished reading, after declaring a variable, looks like the values in memory changed:
atoms[0].resid :0x96fc250
&(atoms[0].resid->ID) :0x96fc25c
**(atoms[0].resid->ID) :1**
atoms[1].resid :0x96fc250
&(atoms[1].resid->ID) :0x96fc25c
**(atoms[1].resid->ID) :1**
atoms[2].resid :0x96fc3ec
&(atoms[2].resid->ID) :0x96fc3f8
(atoms[2].resid->ID) :2
atoms[3].resid :0x96fc3ec
&(atoms[3].resid->ID) :0x96fc3f8
(atoms[3].resid->ID) :2
---------------------------------------
atoms[0].resid :0x96fc250
&(atoms[0].resid->ID) :0x96fc25c
**(atoms[0].resid->ID) :891301941**
atoms[1].resid :0x96fc250
&(atoms[1].resid->ID) :0x96fc25c
**(atoms[1].resid->ID) :891301941**
atoms[2].resid :0x96fc3ec
&(atoms[2].resid->ID) :0x96fc3f8
(atoms[2].resid->ID) :2
atoms[3].resid :0x96fc3ec
&(atoms[3].resid->ID) :0x96fc3f8
(atoms[3].resid->ID) :2
Here is the code. I don't really know what I did wrong
#define FT_GRO 1
using namespace std;
class residue{
public:
residue(){}
residue(const residue& r){atoms=r.atoms; ID=r.ID; name= r.name;}
residue(int n, string s) {name=s;ID=n;}
public:
vector<class atom*> atoms;
int ID;
string name;
atom& addAtom(atom& a) { atoms.push_back(&a); return a;}
};
class atom{
public:
atom(){}
atom(const atom& a){ID=a.ID,name=a.name,coord=a.coord,resid=a.resid ;}
atom(const int anum, const string aname, const point3D& p, residue& res){coord=p; name=aname; resid=&res; ID=anum;}
~atom(){}
public:
point3D coord;
int ID;
string name;
double distance(point3D& p) {return coord.distance(p);}
double distance(atom& p) {return coord.distance(p.coord);}
class residue* resid;
};
int main(){
vector<atom> atoms;
vector<residue> residues;
double box1,box2,box3,x,y,z;
char l[256];
int nr,na;
string sr,sa;
int lastResNum = -1;
string lastResName("");
int nAtomsIn=4;
for(int i =0; i<nAtomsIn;i++){
cin.getline(l,255);
istringstream ssatm(l,ios::in);
ssatm >> setw(5) >> nr >> setw(5) >> sr >> setw(5) >> sa >> setw(5) >>na >> setw(8) >> x >>setw(8) >> y >>setw(8) >> z;
if (lastResNum!=nr || sr!=lastResName){
residues.push_back(residue(nr,sr));
}
point3D p(x,y,z);
atoms.push_back( atom(na,sa,p,residues.back()) );
residues.back().addAtom(atoms.back());
cout << "atoms["<<i<<"].resid :" << atoms[i].resid << endl;
cout << "&(atoms["<<i<<"].resid->ID) :" << &(atoms[i].resid->ID) << endl;
cout << "&(atoms["<<i<<"].resid->ID) :" << (atoms[i].resid->ID) << endl;
lastResNum=nr; lastResName=sr;
}
cout << "---------------------------------------"<<endl;
cin.getline(l,255);
istringstream ssbox(l);
ssbox >> setw(10) >> box1>>setw(10) >> box2>>setw(10) >> box3;
for(int i =0; i<atoms.size();i++){
cout << "atoms["<<i<<"].resid :" << atoms[i].resid << endl;
cout << "&(atoms["<<i<<"].resid->ID) :" << &(atoms[i].resid->ID) << endl;
cout << "&(atoms["<<i<<"].resid->ID) :" << (atoms[i].resid->ID) << endl;
}
return 0;
}
What you're seeing is perfectly normal behaviour -- when you add new elements to a vector, it may get resized, hence all the elements are copied to a new memory location.
If you need a guarantee that existing elements aren't moved in memory, use a different container such as list or set.
std::vector will move memory when it needs more space. It allocates a contiguous block of memory, and when that block fills up, it allocates a bigger block, copies all the elements from the old block to the new one, frees the old block, and moves on.
To prevent the behavior you are seeing, you can do any of a few things to improve your design patter:
1) Change your vectors in main() to store pointers instead of stack options. This way, the object will always be in the same place in memory.
2) Change your class declarations to allow deep copies by implementing a copy-constructor and assignment operator
3) Modify your class heirarchy to remove the circular dependency between your classes. You can do this by having a Residue class, an Atom class, and another class that maps the 2 to each other.
The simplest option will be #1. You'll just need to make sure you clean up memory properly.
Like casablanca said, whenever your vector expands, it change where the objects are in memory.
If you really want to use vectors instead of some other container
1) you can reserve a large piece of memory for your vector. If you have a guarantee that the number of these objects won't exceed a certain bound and you don't mind using up that much memory, then make your vector that large.
2) make them vectors of pointers. If you have a very modern compiler (gcc >= 4.4 for example), you may even have access to the new unique_ptr smart pointer class from C++0x, which lets you use smart pointers in stl containers. These great additions to the language.