Calling member function with reference to pointer - c++

I have a class CaloReader that creates a pointer _calo to an object called Calorimeter containing a grid of cells with an ID number. This pointer is then used to set an ID number to each cell. Futhermore, I have a accessor const Calorimeter& calo() that returns a reference of this pointer. Now, I want to create a function dumpReadoutMap() that prints out all ID numbers of all cells. The function is called from my main file as follows:
#include <iostream>
#include "CaloCell.hh"
#include "CaloGrid.hh"
#include "Point.hh"
#include "Calorimeter.hh"
#include "CaloReader.hh"
int main(){
CaloReader r("calo.dat");
r.calo().dumpReadoutMap();
}
The problem with my code is that the complirer gives the following error:
error: ‘const class Calorimeter’ has no member named ‘dumpReadoutMap’
r.calo().dumpReadoutMap();
The only relevant file for this question is the below as the other ones are correct and cannot be changed.
#ifndef CALOREADER_HH
#define CALOREADER_HH
#include <iostream>
#include <fstream>
#include "Calorimeter.hh"
#include "CaloReaderException.hh"
#include <string>
#include <iomanip>
class CaloReader {
public:
CaloReader(const char* file): _file(file) {
Calorimeter* _calo = 0;
ifstream _file(file);
std::string word;
_file >> word;
_file >> word; //Reads in next word.
if(word=="SIZE") {
int size_x;
int size_y;
_file >> size_x;
_file >> size_y;
_calo = new Calorimeter(size_x,size_y);
}
_file >> word;
while(word=="POSITION") {
int readoutID;
int ix;
int iy;
_file >> readoutID >> ix >> iy;
//std::cout << word << " " << readoutID << " " << ix << " " << iy << std::endl;
_calo->grid().cell(ix,iy)->setID(readoutID);
_file >> word;
}
}
~CaloReader() {}
const Calorimeter& calo() const {
return *_calo;
}
void dumpReadoutMap(std::ostream& os = std::cout) {
for(int x =0; x<size_x; x++) {
for(int y=0; y<size_y; y++) {
os << std::setw(6) << grid().cell(x,y)->getID();
}
os << std::endl;
}
}
private:
Calorimeter* _calo;
std::ifstream _file;
std::string word;
};
#endif

dumpReadoutMap is a method in CaloReader class. So it must be called from a CaloReader object. You should use:
CaloReader r("calo.dat");
r.dumpReadoutMap();

Since calo() returns a const reference, you can't call a non-const member function with it. It's disappointing the error message doesn't explain clearly what the error is.

Related

How to use pointer with struct to refer to the field of each struct

Below code is the normal way to get the input from a text and store it in an array in a structure.
Wanted to ask how can i use pointer to store all these data into the array of structure ? Like p1->Years (this is without array, but how can i apply this to way of writing in below code)
Any better suggestion to use pointer to take in the input?
int years = 4;
struct maju_company {
int Year;
float quarter1, quarter2, quarter3, quarter4, total_sales, average_sales;
};
int main() {
string line;
maju_company p1[years];
fstream yeecinnfile("MajuSales.txt");
if(yeecinnfile.is_open()) {
//ignoring the first four line of code and store the rest of the code
string line1,line2,line3,line4;
getline(yeecinnfile,line1);
getline(yeecinnfile,line2);
getline(yeecinnfile,line3);
getline(yeecinnfile,line4);
while(!yeecinnfile.eof()) {
for(int i =0; i<years; i++) {
yeecinnfile>>p1[i].Year>>p1[i].quarter1>>p1[i].quarter2>>p1[i].quarter3>>p1[i].quarter4;
}
}
for(int i =0; i<years; i++) {
cout<<p1[i].Year<<setw(10)<<p1[i].quarter1<<setw(10)<<p1[i].quarter2<<setw(10)<<p1[i].quarter3<<setw(10)<<p1[i].quarter4<<endl;
}
cout<<endl;
}
}
I see nothing wrong with the way you do this.
However, you could create a pointer to each record inside the loop
maju_company* p = &p1[i];
and then use p-> instead of p1[i]., but I really don't see this as an improvement.
If the reading loop looks too complicated, I would rather move the code to a separate function, perhaps
void read_record(maju_company& company);
or maybe
maju_company read_record();
and then only have to handle a single company inside the function (so no indexing and no ponters there).
I think you wouldn't need pointers at all for your example.
Use a std::vector to hold all your data and then there are other
things from C++ I think you should learn to use, example here :
(if you have questions let me know)
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
// dont use : using namespace std;
struct maju_company_data
{
int year;
float quarter1, quarter2, quarter3, quarter4, total_sales, average_sales;
};
// describe how to stream data to an output stream (like std::cout)
std::ostream& operator<<(std::ostream& os, const maju_company_data& data)
{
os << "-----------------------------------------------------\n";
os << "Company data for year : " << data.year << "\n";
os << "Quarter 1 : " << data.quarter1 << "\n";
os << "Quarter 2 : " << data.quarter1 << "\n";
os << "Quarter 3 : " << data.quarter1 << "\n";
os << "Quarter 4 : " << data.quarter1 << "\n";
os << "\n";
return os;
}
int main()
{
// no need to manage pointers yourself use a vector
std::vector<maju_company_data> company_yearly_data; // give variables a meaningful name
std::ifstream ifile("MajuSales.txt"); // ifstream your using file as input
std::string line1, line2, line3, line4;
// ignore first line
ifile >> line1;
while (ifile >> line1 >> line2 >> line3 >> line4) // probably you need to read a few more lines here
{
maju_company_data data;
// convert read strings to numbers
data.year = std::stoi(line1);
data.quarter1 = std::stof(line2);
data.quarter2 = std::stof(line3);
data.quarter3 = std::stof(line4);
//..
//data.quarter4 = std::stof(line5);
//data.total_sales = std::stof(line6);
company_yearly_data.push_back(data);
};
// this is a range based for loop
// it is prefered since you cant go out of bounds
// const auto& means that data will be an unmodifiable
// reference to each of the structs stored in the vector
for (const auto& data : company_yearly_data)
{
std::cout << data; // since we overloaded << this loop will be nice and clean
}
return 0;
}
A C++ approach to this to overload the istream operator>> and ostream operator<< for your specific type. E.g.
#include <algorithm>
#include <array>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
static constexpr auto years{4};
struct maju_company {
int Year{};
float quarter1{}, quarter2{}, quarter3{}, quarter4{};
float total_sales{}, average_sales{}; // ALWAYS init your floats.
};
auto& operator>>(std::istream& is, maju_company& mc) {
is >> mc.Year
>> mc.quarter1 >> mc.quarter2 >> mc.quarter3 >> mc.quarter4
>> mc.total_sales >> mc.average_sales;
return is;
}
auto& operator<<(std::ostream& os, maju_company const& mc) {
os << mc.Year
<< std::setw(10) << mc.quarter1
<< std::setw(10) << mc.quarter2
<< std::setw(10) << mc.quarter3
<< std::setw(10) << mc.quarter4;
return os;
}
You can then go on to use the type using the std library, e.g.
int main() {
auto p1{std::array<maju_company, years>{}};
{
auto fs{std::fstream("MajuSales.txt")};
if (!fs.is_open()) return -1;
{
// throw away 4 lines
auto dummy{std::string{}};
for (auto i{0}; i < 4; ++i) getline(fs, dummy);
}
std::copy_n(std::istream_iterator<maju_company>{fs},
years,
begin(p1));
}
std::copy(cbegin(p1), cend(p1),
std::ostream_iterator<maju_company>{std::cout, "\n"});
}

C++ String Stream

I'm just learning how to use streams in C++ and I have one question.
I thought that each stream has state true or false. I want to enter each word from the string below and 1 until there is a word, but I get an error:
cannot convert 'std::istringstream {aka std::__cxx11::basic_istringstream<char>}' to 'bool' in initialization
bool canReadMore = textIn;
It should be like:
antilope
1
ant
1
antagonist
1
antidepressant
1
What am I doing wrong?
int main() {
std:: string text = "antilope ant antagonist antidepressant";
std:: istringstream textIn(text);
for(int i = 0; i < 5; i++ ){
std:: string s;
textIn >> s;
bool canReadMore = textIn;
std::cout << s << std:: endl;
std::cout << canReadMore << std:: endl;
}
return 0;
}
``1
Since C++11, std::istringstream operator bool is explicit. What this means is that you must explicitly make the cast yourself:
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string text = "antilope ant antagonist antidepressant";
std::istringstream textIn(text);
for (int i = 0; i < 5; i++) {
std::string s;
textIn >> s;
bool canReadMore = bool(textIn);
std::cout << s << std::endl;
std::cout << canReadMore << std::endl;
}
return 0;
}
Output:
./a.out
antilope
1
ant
1
antagonist
1
antidepressant
1
0
Now, if you use a std::stringstream in a bool context, the conversion will be automatic. This is an idiomatic use:
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string text = "antilope ant antagonist antidepressant";
std::istringstream textIn(text);
std::string s;
while (textIn >> s) {
std::cout << s << "\n";
}
}
Output:
antilope
ant
antagonist
antidepressant

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.

creating files, checking if another one with the same name exists

Code(main.cpp) (C++):
#include <string>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
//general vars
std::ofstream ofs;
std::ifstream ifs;
std::stringstream ss;
//spamFiles vars
std::string defPath;
int defAmt;
void spamFiles(std::string paramPath);
int main(int argc, const char * argv[])
{
srand(time_t(NULL));
std::cout << "Enter the amount of files: ";
std::cin >> ::defAmt;
std::cout << "Now enter the target path: ";
std::cin >> ::defPath;
::spamFiles(::defPath);
std::cout << defAmt << " files were created." << std::endl;
return 0;
}
void spamFiles (std::string paramPath){
//system("open -a Terminal .");
for(int i = 0; i < ::defAmt; i++){
std::string tempS;
int ranNum = rand() % 501;
ss << ranNum;
std::string ssResult = ss.str();
std::string finalPath = ::defPath + ssResult + ".txt";
ifs.open(finalPath);
if(ifs.good()){
finalPath += "dupe.txt";
while(ifs.good()){
finalPath += "dupe.txt";
ifs.open(finalPath);
}
}
ofs.open(finalPath);
ofs << "";
ofs.close();
ss.str(std::string());
}
return;
}
My problem is following.
Whenever I run this and enter, lets say 53 as for the amount, in the end it'll never create the full amount of files. It's always scaled.
Here's an example.
Defined Amont: 300 -> What I Get: 240
Defined Amount: 20 -> What I get: 15
Defined Amount: 600 -> What I get: 450
Thanks in advance.
Based on the logic of your code, you are creating a file if your ifstream object is not 'good()'. If some files aren't being created, then the error lies here.
With some digging, you'll find that the constructor for an ifstream object does not take a string, but instead a char *.
Adding a c_str() to your 'finalPath' variable should take care of this issue.
Some things to note:
You've forgotten to include fstream and iostream.
When digging into problems like this, don't use random numbers as your first test case. It was easier for me to replicate your issue by just trying to create files in numerical order.
Also don't forget 'close()' your ifstreams!
My adaptation of the code:
#include <string>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
#include <fstream>
#include <iostream>
//general vars
std::ofstream ofs;
std::ifstream ifs;
std::stringstream ss;
//spamFiles vars
std::string defPath;
int defAmt;
void spamFiles(std::string paramPath);
int main(int argc, const char * argv[])
{
srand(time_t(NULL));
std::cout << "Enter the amount of files: ";
std::cin >> ::defAmt;
std::cout << "Now enter the target path: ";
std::cin >> ::defPath;
::spamFiles(::defPath);
std::cout << defAmt << " files were created." << std::endl;
return 0;
}
void spamFiles (std::string paramPath){
//system("open -a Terminal .");
for(int i = 0; i < ::defAmt; i++){
std::string tempS;
int ranNum = rand() % 501;
ss << ranNum;
std::string ssResult = ss.str();
std::string finalPath = ::defPath + ssResult + ".txt";
ifs.open(finalPath.c_str());
while(ifs.good()){
finalPath += "dupe.txt";
ifs.open(finalPath.c_str());
}
ifs.close();
std::cout << finalPath << std::endl;
ofs.open(finalPath.c_str());
ofs << "";
ofs.close();
ss.str(std::string());
}
return;
}

Parse a File with C++

I have created code that will execute a file and then will execute code and store that code into a .csv filer shown below
#include <string>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <fstream>
using namespace.std;
int main(){
int foo = 10;
for(int i =1; x<=8 x++){
std::stringstream ss;
ss << "echo " << foo << " | ./triad >> scaling.csv"<<'\n';
std::cout << ss.str().c_str() <<std::endl;
system(ss.str().c_str());
foo=foo*10
}
return 0;
}
The triad program is one that I am given and cannot change. I run basically 10 iterations on it and print the output of that to a scaling.csv, to give me the following output
Length: 10 MFLOP/s: 2541.29
Length: 100 MFLOP/s: 2515.85
Length: 1000 MFLOP/s: 3616.75
and so on...
does anyone know how to parse that file so instead my scaling.csv will look something like this
Key,Value
10,2541.29
100,2515.85
1000,3616.75
Again what gets printed out by triad I cannot change.
Simple:
int main()
{
string s;
int key; float val;
ifstream out("out.txt");
ofstream in("in.txt);
in >> s;
in >> key; // key == 10
in >> s;
in >> val; // val == 2541.29
}
Put this into a function and you have:
void extract(std::istream& in, int& key, float& val)
{
// same as above
}
int main()
{
int key; float val;
while (in)
{
extract(in, key, val);
out << key << ", " << val << std::endl;
}
}
But we're performing the input after we check the stream. This can cause problems. Let's have the extract function return a reference to the stream:
std::ios& extract(std::istream& in, int& key, float& val)
{
// same as above
}
int main()
{
int key; float val;
while (extract(in, key, val))
// ^^^^^^^^^^^^^^^^^^^^^
{
out << key << ", " << val << std::endl;
}
}