C++: error 'std::string' is private - c++

So, for class, I have to write a program that simulates a horse race. It's our first major project involving classes. I'm stuck receiving the error mentioned in the subject. Now, I have struggled with pointers since they were introduced, so I have zero doubt this is where my overall problem lies. I've asked my professor for help, but he's not replying to my emails. I've also contacted friends, etc. and no one is getting back to me.
This is my header file (Horse.h):
#ifndef HORSE_H
#define HORSE_H
#include <string>
class Horse
{
private:
std::string name;
std::string jockey;
int maxSpeed;
int distanceTraveled;
int racesWon;
public:
Horse(std::string, std::string);
void runOneSecond(int);
void sendToGate();
void displayHorse (double);
};
#endif // HORSE_H
Here is my Horse.cpp:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>
#include "Horse.h"
using namespace std;
Horse::Horse(string name, string jockey)
{
srand (time(NULL));
int maxSpeed = rand() % 30 + 1;
distanceTraveled = 0;
};
void Horse::runOneSecond(int maxSpeed)
{
srand (time(NULL));
distanceTraveled = rand() % maxSpeed;
};
void Horse::sendToGate()
{
distanceTraveled = 0;
};
void Horse::displayHorse(double raceDistance)
{
int percentage;
for (int i = 0; i < numberOfHorses; i++)
{
cout << "|";
}
};
And here is my main.cpp:
#include <iostream>
#include <string>
#include <cctype>
#include "Horse.h"
using namespace std;
int main()
{
double raceDistance = 0;
int numberOfHorses = 0;
char choice = 'Y';
string name;
string jockey;
cout << "Enter the number of horses for the race: ";
cin >> numberOfHorses;
Horse** horsePtr = new Horse* [numberOfHorses];
// Trouble section.
for (int i = 0; i < numberOfHorses; i++)
{
cout << "Fill in the name of the horse: ";
cin >> horsePtr[i]->name;
cout << "Fill in the name of the jockey: ";
cin >> horsePtr[i]->jockey;
}
cout << "How long should the race be (in meters): ";
cin >> raceDistance;
cout << endl;
cout << "Start!" << endl;
for (int i = 0; i < numberOfHorses; i++)
{
horsePtr[i]->sendToGate();
}
for (int i = 0; i < numberOfHorses; i++)
{
horsePtr[i]->displayHorse(raceDistance);
}
cout << "Show the next second of the race? ";
cin >> choice;
while(toupper(choice) == 'Y')
{
if (toupper(choice) == 'Y')
{
for (int i = 0; i < numberOfHorses; i++)
{
horsePtr[i]->runOneSecond(maxSpeed);
horsePtr[i]->displayHorse(raceDistance);
}
}
}
return 0;
}
Here is the error:
Horse.cpp: In member function ‘void Horse::displayHorse(double)’:
Horse.cpp:29:23: error: ‘numberOfHorses’ was not declared in this scope
for (int i = 0; i < numberOfHorses; i++)
^
In file included from main.cpp:4:0:
Horse.h: In function ‘int main()’:
Horse.h:8:17: error: ‘std::string Horse::name’ is private
std::string name;
^
main.cpp:25:25: error: within this context
cin >> horsePtr[i]->name;
^
In file included from main_dmj8t6.cpp:4:0:
Horse.h:9:17: error: ‘std::string Horse::jockey’ is private
std::string jockey;
^
main.cpp:27:25: error: within this context
cin >> horsePtr[i]->jockey;
^
main.cpp:55:35: error: ‘maxSpeed’ was not declared in this scope
horsePtr[i]->runOneSecond(maxSpeed);
^

You cannot access a private member of a class. In your example, your Horse class contains 5 private members:
class Horse
{
private:
std::string name;
std::string jockey;
int maxSpeed;
int distanceTraveled;
int racesWon;
public:
};
These private members can be accessed within the Horse class methods, and by any friend classes; however: nothing else can access them.
int main()
{
// Trouble section.
for (int i = 0; i < numberOfHorses; i++)
{
cout << "Fill in the name of the horse: ";
cin >> horsePtr[i]->name; <--
cout << "Fill in the name of the jockey: ";
cin >> horsePtr[i]->jockey; <--
}
}
On the two lines marked, you are attempting to access the private members of Horse and the compiler won't allow it.
Consider making those variables public to Horse, or providing setter functions for them:
class Horse
{
private:
std::string name;
std::string jockey;
int maxSpeed;
int distanceTraveled;
int racesWon;
public:
void SetName(std::string s) { name = s; }
void SetJockey(std::string s) { jockey = s; }
};
int main()
{
std::string jockeyName;
std::cout << "Enter a name for the jockey: ";
std::cin >> jockeyName;
Horse* h = new Horse;
h->SetJockey(jockeyName);
}
You are providing a public constructor for Horse that takes two std::string though (neither which you are using) so you could just pass the relevant information to the Horse:
Horse::Horse(std::string n, std::string j) : name(n), jockey(j)
{
// Other things...
}
int main()
{
Horse* h = new Horse("Phar Lap", "Jim Pike");
}
Note that my two examples are just matching your current code. Your arrays should be replaced by std::vector and pointers, if required, should be replaced by std::unique_ptr (or std::shared_ptr, whichever suits your needs).

Related

simple race game with dynamic array in c++

I was doing homework for a C++ game that we have to do from CO SCI 136 class and the instructions states:
Modify your Homework 4 Problem 1 solution thus:
Replace the array with a dynamic array
Read the winning points M from a file
Read the number of players N from a file
Read the player names from a file.
I am using Visual Studio 2017 and I am having trobule with these errors:
Error C2664 'void Player::setName(std::string &)': cannot convert argument 1 from 'const std::string' to 'std::string &' player.cpp 7
Error C2511 'void Player::setName(const std::string &)': overloaded member function not found in 'Player' player.cpp 18
Error C2597 illegal reference to non-static member 'Player::name' player.cpp 19
Is there any way to fix these errors?
Here are my codes of
player.h
#pragma once
#include <string>
using namespace std;
class Player
{
private:
string name;
int points;
bool skipturn = false;
public:
Player(const string& new_name = "No Name");
string getName() const;
int getPoints() const;
void setName(string& new_name);
void setPoints(int new_points);
void setLossHalfPoints();
void setSkipTurn(bool isSkip);
bool isSkipTurn();
};
player.cpp
#include <string>
using namespace std;
#include "player.h"
Player::Player(const string& new_name)
{
setName(new_name);
}
string Player::getName() const
{
return name;
}
int Player::getPoints() const
{
return points;
}
void Player::setName(const string& new_name)
{
name = new_name;
}
void Player::setPoints(int new_points)
{
points = new_points;
}
void Player::setLossHalfPoints()
{
this->points /= 2;
}
void Player::setSkipTurn(bool isSkip)
{
this->skipturn = isSkip;
}
bool Player::isSkipTurn()
{
return this->skipturn;
}
source.cpp
#include "stdafx.h"
#include <iostream>
#include <string>
#include <ctime>
#include <iomanip>
#include <random>
#include<fstream>
#include "player.h"
using namespace std;
int main()
{
int M;
int N;
Player *player; //Declaring as a dynamic array
player = new Player[N];
string *names;
names = new string[N];
ifstream file, file1, file2; //opening the file in read mode
string line;
file.open("Mdata.dat");
file >> M; //Reading the M data from the file
file.close();
file1.open("Ndata.dat");
file1 >> N; //Reading the N data from the file
file1.close();
file2.open("names.dat");
if (file2.is_open()) //if the file is open
{
while (!file2.eof()) //while the end of file is NOT reached
{
getline(file2, line); //get one line from the file
for (int i = 0; i<N; i++)
{
names[i] = line; //reading names from file into names array
}
}
file2.close();
}
for (int i = 0; i < N; i++) //setting the player names from names array
{
player[i].setName(names[i]); player[i].setPoints(0);
}
default_random_engine dre(17890714);
uniform_int_distribution<int> player_uid(0, N - 1);
uniform_int_distribution<int> dice_uid(1, 6);
int index = player_uid(dre);
do
{
index = (index + 1) % N;//implements circular array
if (player[index].isSkipTurn())
{
cout << player[index].getName() << '/' << setw(2) << "skip turn" << endl;
player[index].setSkipTurn(false);// clear skip turn
index = (index + 1) % N;//implements circular array
}
int die1 = dice_uid(dre);
int die2 = dice_uid(dre);
int points = player[index].getPoints();
player[index].setPoints(points + die1 + die2);
if (player[index].getPoints() > M)
{
player[index].setLossHalfPoints();// set half of then points
player[index].setSkipTurn(true);// set skip turn
cout << player[index].getName() << '/' << setw(2) << player[index].getPoints() << '/' << setw(2) << player[index].getPoints() * 2 << endl;
}
else {
cout << player[index].getName() << '/' << setw(2) << die1 + die2 << '/' << setw(2) << player[index].getPoints() << endl;
}
} while (player[index].getPoints() != M);
cout << player[index].getName() << " wins" << endl;
system("pause");
return 0;
}
Let's look at the compiler error.
Error C2664 'void Player::setName(std::string &)': cannot convert argument 1 from 'const std::string' to 'std::string &' player.cpp 7
It is complaining that it cannot convert const std::string to std::string when calling the setName() function at line 7 of player.cpp. But we have a setName function in the player class, right? What's wrong?
If you look at it more carefully in your Player.h, the declaration of the function setName is missing the const attribute.
void setName(string& new_name);
If you add const to this that will solve it.

Passing data types to C++ class contructor

I extremely need to pass data types to the constructor of classes. I’m working on image processing (till now in Matlab) and now need to use ITK and VTK libraries. In fact, my images are coming from different types and sizes. Unfortunately, I don’t know how to pass a data type to my classes. It’s really painful to have different copies of same classes with different data types!!!
Here is a very simple example to express what I mean and need. In this example, I’m going to create a dynamic array of “int” type. This exaple works well but I don't know how to employ templates. Could you please let me know how I can change the code to be able define any type of dynamic array?
Thanks in advance,
Main
#include "stdafx.h"
#include <iostream>
#include <string>
#include "Myclass.h"
using namespace std;
int main()
{
Myclass c1;
system("pause");
return 0;
}
Class definition:
Myclass.h
class Myclass
{
public:
Myclass();
~Myclass();
private:
int size;
int* my_dynamic_array;
void SetPrivate();
};
Myclass.cpp
#include "stdafx.h"
#include "Myclass.h"
#include <iostream>
using namespace std;
Myclass::Myclass()
{
cout << "Please enter the size of array: ";
cin >> size;
my_dynamic_array = new int[size];
SetPrivate();
}
void Myclass::SetPrivate() {
cout << "\n\nPlease enter " << size << " numbers for the array elements...";
for (int i = 0; i < size; i++) {
cout << "\n\n#" <<i+1<<" : ";
cin >> my_dynamic_array[i];
}
}
Myclass::~Myclass()
{
delete[] my_dynamic_array;
}
Not commenting on whether you could use vector instead of int *my_dynamic_array, I just translated your code into a template. Hope it helps somehow:
template<typename T>
class ImageClass {
public:
ImageClass<T>() {
cout << "Please enter the size of array: ";
cin >> this->size;
my_dynamic_array = new T[this->size];
SetPrivate();
}
void SetPrivate() {
cout << "\n\nPlease enter " << this->size << " numbers for the array elements...";
for (int i = 0; i < this->size; i++) {
cout << "\n\n#" <<i+1<<" : ";
cin >> my_dynamic_array[i];
}
}
protected:
int size;
T *my_dynamic_array;
};
int main() {
ImageClass<int> ic_i;
ImageClass<double> ic_d;
}

Iterate over array of objects from txt file

I have file with records separated by comas:
cities.txt:
1,NYC
2,ABQ
...
I would like to iterate over each row: ids and names. I have created the code:
#include <iostream>
#include <string>
using namespace std;
class City {
int id;
string name;
public:
City() {}
City(int id, int name)
{
this->id = id;
this->name = name;
}
void load_file()
{
ifstream v_file("cities.txt");
if (v_file.is_open()) {
while (!v_file.eof()) {
//...
}
}
v_file.close();
}
}
int main()
{
City array_city[1000];
array_city.load_file();
return 0;
}
Could you tell me how to load all rows to array array_city and iterate over it? I don't know what to place in while block in load_file method. I don't know weather, the method load_file should have void type. Unfortunately I have to do it on arrays.
It's not a good idea to use EOF in a while loop. Read more in Why is iostream::eof inside a loop condition considered wrong?
In c++, vectors should be preferred over arrays. However, your teacher knows something more to suggest using an array here. For that reason I am providing a solution with an array:
Read the file line by line
Extract the id and the string
Assign it to the i-th cell of the array
Code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class City {
int id;
string name;
public:
City() {}
City(int id, string name) : id(id), name(name)
{
}
void print()
{
cout << "ID = " << id << ", name = " << name << endl;
}
};
void load_file(City* cities, const int n)
{
ifstream v_file("cities.txt");
if (v_file.is_open()) {
int number, i = 0;
string str;
char c;
while (v_file >> number >> c >> str && c == ',' && i < n)
{
//cout << number << " " << str << endl;
cities[i++] = {number, str};
}
}
v_file.close();
}
int main()
{
City cities[4]; // assuming there are 4 cities in the file
load_file(cities, 4);
for(unsigned int i = 0; i < 4; ++i)
cities[i].print();
return 0;
}
Same solution with std::vector, if you are interested. =) If you haven't been taught about them, I suggest you skip that part and come back later when you do that in the course.
Use a vector of City. Read the file line by line, and push back into the vector every line you read, by constructing an instance of your class, and you are done!
Example:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
class City {
int id;
string name;
public:
City() {}
City(int id, string name) : id(id), name(name)
{
}
void print()
{
cout << "ID = " << id << ", name = " << name << endl;
}
};
void load_file(vector<City>& cities)
{
ifstream v_file("cities.txt");
if (v_file.is_open()) {
int number;
string str;
char c;
while (v_file >> number >> c >> str && c == ',' && i < n)
{
//cout << number << " " << str << endl;
cities.push_back({number, str});
}
}
v_file.close();
}
int main()
{
vector<City> cities;
load_file(cities);
for(unsigned int i = 0; i < cities.size(); ++i)
cities[i].print();
return 0;
}
Input:
Georgioss-MacBook-Pro:~ gsamaras$ cat cities.txt
1,NYC
2,ABQ
3,CCC
4,DDD
Output:
Georgioss-MacBook-Pro:~ gsamaras$ g++ -Wall -std=c++0x main.cpp
Georgioss-MacBook-Pro:~ gsamaras$ ./a.out
ID = 1, name = NYC
ID = 2, name = ABQ
ID = 3, name = CCC
ID = 4, name = DDD

C++ Initializing and Functions from Derived Class from Vector of Pointer Base

I have a problem where I have 2 classes, Word and Noun. Noun is derived from Word.
All Words and Nouns are to be stored in a single vector hence why I require it being in pointer.
The problem is I can't seem to initialize or call functions from the derived class Noun.
I can pushback for a new Word but not for a Noun.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Word{
protected:
string wordName, def, type;
public:
Word();
Word(string wordName, string def, string type) {
this->wordName = wordName;
this->def = def;
this->type = type;
};
void getWord() {
cout << wordName << endl;
}
void getDef() {
cout << def << endl;
}
void getType() {
cout << type << endl;
}
};
class Noun : public Word{
public:
Noun();
Noun(string wordName, string type, string def);
};
int main(){
vector <Word*> wordVector;
for (int i = 0; i < 2; i++)
{
string wordName, def, type;
cin >> wordName;
cin >> def;
cin >> type;
cout << endl;
wordVector.push_back(new Noun(wordName, def, type)); //new Word(wordName, def, type) works
}
for (int i = 0; i < 2; i++)
{
wordVector[i]->getWord(); //how do you call the function from Noun?
wordVector[i]->getDef();
wordVector[i]->getType();
}
system("pause");
return 0;
}
It comes out with 1 unresolved external symbol.
There are too many things wrong with this code, so allow me to present a correct, complete rewrite that does what you mean:
#include <iostream>
#include <memory> // for std::unique_ptr
#include <string>
#include <vector>
class Word
{
private:
std::string wordName, def, type;
public:
virtual ~Word() = default;
Word(std::string w, std::string d, std::string t)
: wordName(std::move(w))
, def(std::move(d))
, type(std::move(t)) {}
void printWord() const { std::cout << wordName << '\n'; }
void printDef() { std::cout << def << '\n'; }
void printType() const { std::cout << type << '\n'; }
};
class Noun : public Word
{
public:
using Word::Word;
};
int main()
{
std::vector<std::unique_ptr<Word>> wordVector;
for (int i = 0; i != 2; ++i)
{
std::string w, d, t;
if (!(std::cin >> w >> d >> t))
{
std::cerr << "Failed to read input!\n";
continue;
}
wordVector.push_back(std::make_unique<Noun>(
std::move(w), std::move(d), std::move(t)));
}
for (const auto& wp : wordVector)
{
wp->printWord();
wp->printDef();
wp->printType();
}
}
A completely unsorted and incomplete set of issues that I corrected:
Memory management (std::unique_ptr)
Virtual destructor for deletion through base
No nonsensical default constructors
Inheriting constructors rather than manual forwarding
Properly named member functions
Const correctness
No superfluous semicolons
No superfluous std::endl
Not abusing namespace std
Range-based for loop
I/O error handling
Initialize rather than assign
Enable move optimizations
No raw new
Correct access level for private members (exposed via member functions)
I think you just forgot to initialize the superclass constructor In your Noun class try this
class Noun : public Word{
public:
Noun();
Noun(string wordName, string type, string def): Word(wordName, type, def){};
};
I have tested it and it worked.
Also theres a light modification in you main(). just a slight. so that i can see what input it is asking for.
int main(){
vector <Word*> wordVector;
for (int i = 0; i < 2; i++)
{
string wordName, def, type;
cout<< "entere name";
cin >> wordName;
cout<< "entere def";
cin >> def;
cout<< "entere type";
cin >> type;
cout << endl;
wordVector.push_back(new Noun(wordName, def, type)); //new Word(wordName, def, type) works
}
for (int i = 0; i < 2; i++)
{
wordVector[i]->getWord(); //how do you call the function from Noun?
wordVector[i]->getDef();
wordVector[i]->getType();
}
system("pause");
return 0;
}

Why is this code accessing vector out of its range?

So, I'm trying bring over some code to a Qt project I'm working on. The Motion class imports some control points from .txt file into the public member variable ctrlPos using fstream. When I use readCtrlPositions and then try to access ctrlPos with writePositions, for example, I get the error "vector subscript out of range".
There is a lot more code, but hopefully this should be sufficient to answer my question. I'm also a bit of a novice, so with any luck it's not something too stupid.
Motion class header:
#ifndef MOTION_H
#define MOTION_H
#include <vector>
#include "DualQuaternion.h"
class Motion
{
public:
virtual ~Motion();
virtual void readCtrlPositions(char*, char*);
virtual void writePositions(char*);
virtual void drawCtrlPositions();
virtual void set(int, vector<DualQuaternion>);
virtual pair<int, vector<DualQuaternion>> get();
public:
vector<DualQuaternion> ctrlPos, c;
int numberOfPositions;
};
#endif
Motion class:
#include <stdlib.h>
#include <GL\glut.h>
#include "motion.h"
#include "Quaternion.h"
#include "hMatrix.h"
#include "hPoint.h"
using namespace std;
void Motion::readCtrlPositions(char *fileNameArg, char *t)
{
ifstream inFile(fileNameArg, ios::in);
if (!inFile)
{
cerr<<"File" << fileNameArg << "could not be opened" << endl;
exit(1);
}
int i;
inFile >> numberOfPositions;
Quaternion *RotationQuaternion = new Quaternion[numberOfPositions];
for (i = 0; i<numberOfPositions; i++)
inFile >> RotationQuaternion[i];
if (t == "v")
{
Vector *TranslationVector = new Vector[numberOfPositions];
for (i = 0; i<numberOfPositions; i++)
inFile >> TranslationVector[i];
ctrlPos.clear();
for (i = 0; i<numberOfPositions; i++)
{
DualQuaternion dQ(RotationQuaternion[i], TranslationVector[i]);
ctrlPos.push_back(dQ);
cout << "first position from input: " << ctrlPos[i] << endl;
}
delete[] TranslationVector;
}
else if (t == "q")
{
Quaternion *TranslationQuaternion = new Quaternion[numberOfPositions];
for (i = 0; i<numberOfPositions; i++)
inFile >> TranslationQuaternion[i];
ctrlPos.clear();
for (i = 0; i<numberOfPositions; i++)
{
DualQuaternion dQ(RotationQuaternion[i], TranslationQuaternion[i]);
ctrlPos.push_back(dQ);
cout << "first position from input: " << ctrlPos[i] << endl;
}
delete[] TranslationQuaternion;
}
delete[] RotationQuaternion;
}
void Motion::writePositions(char *fileNameArg)
{
ofstream outFile(fileNameArg, ios::out);
if (!outFile)
{
cerr<<"File" << fileNameArg << "could not be opened for writing" << endl;
exit(1);
}
int i;
outFile << numberOfPositions << endl << endl;
for (i = 0; i<numberOfPositions; i++)
outFile << ctrlPos[i].GetReal();
outFile << endl;
for (i = 0; i<numberOfPositions; i++)
outFile << ctrlPos[i].GetDual();
}
void Motion::set(int n, vector<DualQuaternion> p)
{
int i;
numberOfPositions = n;
ctrlPos.clear();
for (i = 0; i<numberOfPositions; i++)
ctrlPos.push_back(p[i]);
}
pair<int, vector<DualQuaternion>> Motion::get()
{
return make_pair(numberOfPositions, ctrlPos);
}
void Motion::drawCtrlPositions()
{
vector <hMatrix> homogeneousMatricesForCtrlPositions;
for (int i=0; i<numberOfPositions; i++)
{
homogeneousMatricesForCtrlPositions.push_back(ctrlPos[i].dualQuaternionToHomogeneousMatrix().transpose());
double MatrixforOpenGLStack[16];
for (int i1=0; i1<4; i1++)
for (int i2=0; i2<4; i2++)
MatrixforOpenGLStack[4*i1+i2] = homogeneousMatricesForCtrlPositions.at(i).m[i1][i2];
::glPushMatrix();
::glMultMatrixd(MatrixforOpenGLStack);
glutSolidTeapot(0.15);
::glPopMatrix();
}
}
Motion::~Motion()
{
}
Sample code where error occurs in Qt program:
static Curve m;
m.readCtrlPositions("input.txt", "v");
m.writePositions("output.txt"); //<--vector subscript out of range
m.readCtrlPositions("output.txt", "q");
ctrlPos = m.get().second;
numberOfPositions = m.get().first;
In readCtrlPositions, t is a char*, so nor t=="v", nor t=="q" will be evaluated to true (it would return true if the two pointers were having the same address). So your function will set numberOfPositions to a non zero value but will never fill ctrlPos vector with any value.
Later, you'll try to access ctrlPos elements from 0 to numberOfPositions (not zero), while ctrlPos vector is empty. That's why you are reported to access the vector out of its range!
Replace char* by std::string is an easy way to fix the problem. If you need to keep the parameter as a char*, then use strcmp to compare string values rather than pointers.
I would also strongly recommend that you remove your numberOfPositions attribute and simply use ctrlPos.size() instead. It would have prevented a crash in this case by guaranteeing your class attributes integrity.