Variable scope error when declaring friend function - c++

Friend functions can't access variables of the classes
I'm having a problem with several friend functions not being able to access the variables in classes where they have been declared as friends.
The actual error text is:
error: 'fid' was not declared in this scope. this repeats for the other private variables.
The same error is given for three functions, read, negative, and write.
A couple of notes:
1) This lab requires that I write the code so that the functions can be used by both classes.
I'm compiling this in windows with code::blocks using g++ and I've also tried compiling my code in ubuntu using g++ from the terminal using the -g flag and I get the same error both times.
Any suggestions you have would be greatly appreciated.
Header File
#ifndef PXMUTILS_H
#define PXMUTILS_H
#include <cstdio>
#include <cstdlib>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
using namespace std;
typedef unsigned char uchar;
class pgm
{
public:
pgm();
~pgm();
void read(string &);
void negative();
void write(string);
friend void read (const string &);
friend void write(string);
friend void negative();
private:
int nr;
int nc;
int mval;
int ftyp;
string fid;
uchar **img;
};
class ppm
{
public:
ppm();
~ppm();
void read(string &);
void negative();
void write(string);
friend void read (const string &);
friend void write (string);
friend void negative ();
private:
int nr;
int nc;
int mval;
int ftyp;
string fid;
uchar **img;
};
#endif
C++ program
#include <cstdio>
#include <cstdlib>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
#include "pxmutils.h"
using namespace std;
typedef unsigned char uchar;
uchar ** newimg(int nr, int nc, int ftyp)
{
uchar **img=new uchar *[nr];
img[0]=new uchar [nr*nc*ftyp];
for(int i=1; i<nr; i++)
{
img[i]=img[i-1]+nc*ftyp;
}
return img;
}
void deleteimg(uchar **img)
{
if(img)
{
if(img[0])
{
delete [] img[0];
}
delete [] img;
}
}
void read (const string &fname)
{
ifstream fin(fname.c_str(), ios::in);
if(!fin.is_open())
{
cerr<<"Could not open "<<fname<<endl;
exit(0);
}
fin >>fid
>>nc
>>nr
>>mval;
while (fin.get() != '\n') { /*skip to EOL */ }
img=newimg(nr, nc);
fin.read((char *)img[0], nr*nc);
fin.close();
}
void set_cmap(string mname)
{
}
void negative()
{
for(int i=0; i<nr; i++)
{
for(int j=0; j<nc; j++)
{
int t=img[i][j];
img[i][j]=(255-t);
}
}
}
void write(string fname)
{
ofstream fout (fname.c_str(), ios::out);
size_t dp;
if ((dp = fname.rfind(".pgm")) != string::npos)
{
fout<<"P5"<<endl;
}
if((dp= fname.rfind(".ppm")) != string::npos)
{
fout<<"P6"<<endl;
}
fout<<nc<<" "<<nr<<endl;
fout<<mval<<endl;
for(int i=0; i <nr; i++)
{
for (int j=0; j<nc; j++)
{
fout<<img[i][j]<<" ";
}
fout<<endl;
}
fout.close();
}
pgm::pgm()
{
nr=0;
nc=0;
mval=0;
ftyp=1;
fid="";
img=NULL;
}
pgm::~pgm()
{
deleteimg(img);
}
ppm::ppm()
{
nr=0;
nc=0;
mval=0;
ftyp=1;
fid="";
img=NULL;
}
ppm::~ppm()
{
deleteimg(img);
}
Program to test functions
#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;
#include "pxmutils.h"
int main(int argc, char *argv[])
{
if (argc == 1) {
cerr << "No input file specified!\n";
exit(0);
}
string fname = argv[1];
size_t dp;
if ((dp = fname.rfind(".pgm")) == string::npos) {
cout << "PGM error: file suffix " << fname
<< " not recognized\n";
exit(0);
}
fname.erase(dp);
pgm img_g;
ppm img_c;
img_g.read(fname+".pgm");
if (argc == 3)
img_c.set_cmap(argv[2]);
img_c = img_g;
img_g.negative();
img_g.write(fname+"_n.pgm");
img_c.write(fname+"_c.ppm");
}

fin >>fid
>>nc
>>nr
>>mval;
while (fin.get() != '\n') { /*skip to EOL */ }
In this code, fid, nc, nr etc are undefined. You need to use the class instance to be able to access them, they don't exist by themselves.
Your functions don't accept the class objects as parameters, so how are you going to read into them?

You should have another think of your design. It is best to avoid friend functions if possible,

You need to go a bit back to basics. When you define non-static members of a class you are defining attributes or operations of the objects of the class, but those attributes don't exist by themselves, only as part of the instances of the class.
This concept is orthogonal to access and access specifiers, that is, this is so regardless of the members being public, protected or private. Once you have an instance, when your try to access those members the access specifiers come into play, and there is where friendship comes into play: it will grant your code access to members that would otherwise be inaccessible (private or protected outside of the inheritance hierarchy).
The problem in your code is that you don't have an object, and thus cannot access the members of the object. You will need to either create or pass an object of the appropriate type to the functions.
There are other problems in the code, like for example, the memory allocations inside newimg look a little suspicious (what were you intending to allocate?) but that is outside of the scope of this question.

Related

Segmention fault when saving a vector to binary file c++

I tried to make a program to write lists and save them to binary files so nobody can change it and its size less than the text file. I tried to use three vectors inside each other, but when reading it gives a segmentation fault.
Here is the writing code:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
vector<vector<vector<string>>> test;
int main() {
test.push_back({{"Hello"}});
cout << test[0][0][0];
ofstream otst("test.bin",ios::binary);
otst.write((char*)&test,sizeof(test));
return 0;
}
And here is the reading code:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
vector<vector<vector<string>>> test;
int main() {
ifstream tst("test.bin",ios::binary);
tst.read((char*)&test,sizeof(test));
return 0;
}
You are trying to write() and read() the outer vector object exactly as it appears in memory. That will not work, since it contains pointers to data that is stored elsewhere in memory. You must serialize its data instead, and then deserialize it in the reading code, eg:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdint>
using namespace std;
template<typename T>
void write(ofstream &out, const T &value)
{
out.write(reinterpret_cast<const char*>(&value), sizeof(value));
}
void write(ofstream &out, const string &value)
{
uint32_t size = str.size();
write(out, size);
if (size > 0) {
out.write(str.c_str(), size);
}
}
template<typename T>
void write(ofstream &out, const vector<T> &vec)
{
uint32_t size = vec.size();
write(out, size);
for(const auto &elem : vec) {
write(out, elem);
}
}
int main()
{
vector<vector<vector<string>>> test;
test.push_back({{"Hello"}});
cout << test[0][0][0];
ofstream otst("test.bin", ios::binary);
otst.exceptions(ofstream::failbit);
write(otst, test);
return 0;
}
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdint>
using namespace std;
template<typename T>
void read(ifstream &in, T &value)
{
in.read(reinterpret_cast<char*>(&value), sizeof(value));
}
void read(ifstream &in, string &str)
{
uint32_t size;
read(in, size);
str.resize(size);
if (size > 0) {
in.read(&str[0]/* or: str.data() */, size);
}
}
template<typename T>
void read(ifstream &in, vector<T> &vec)
{
uint32_t size;
read(in, size);
vec.resize(size);
for(auto &elem : vec) {
read(in, elem);
}
}
int main()
{
vector<vector<vector<string>>> test;
ifstream itst("test.bin",ios::binary);
itst.exceptions(ifstream::failbit);
read(itst, test);
return 0;
}
UPDATE:
If you can use Boost, it has its own serialization framework, which natively supports serializing vectors. See C++ Boost serialization of a matrix of vectors
I had a similar issue with writing 3d arrays from the heap to memory and reading it. I don't know if it would solve your issue but it's possible that each vector dimension contains a pointer to another vector until the program gets to the base vector so the data that is written is just the pointer of the vectors which would not be part of the program when you read from the binary file. This would result in the program writing pointers to unallocated memory which would cause a segmentation fault. Another possible problem is that you read to sizeof(test) which might not have allocated space for non-existent elements(I haven't worked with vectors a ton so I don't know how stack allocation works with them). My money is on the first idea though which is good because it is also easier to fix. Just right simple recursion in your write process for example:
int main() {
fstream fs;
fs.open("test.bin",ios::out | ios::binary);
vector<vector<vector<string>>> test;
for(int h = 0; h < test[0].size(); h++) {
for(int w = 0; w < test[0][0].size(); w++) {
for(int t = 0; t < test[0][0][0].size(); t++) {
fs.write((char*)&test[h][w][t], sizeof(test));
}
}
}
return 0;
}
I would recommend however, that if you can yous should just use a really large array like a [1000][1000][1000] array. It is easier to use set amounts of numbers.

[error in compilation .its is a deleted function]

I am getting below error:
2 IntelliSense: function "std::basic_ifstream<_Elem, _Traits>::basic_ifstream(const std::basic_ifstream<_Elem, _Traits>::_Myt &) [with _Elem=char, _Traits=std::char_traits<char>]" (declared at line 818 of "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\fstream") cannot be referenced -- it is a deleted function c:\Users\varunk\Documents\Visual Studio 2013\Projects\hashmaptest\hashmaptest\hashmaptest.cpp 12 48 hashmaptest
Here is my code which is showing the error:
// hashmaptest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
Init ini;
ifstream file("D:/test.txt", ios::in);
ini.filterng_three_addId_on_location_and_time(file);
file.close();
// Node shoom = Node ("ram", 14);
// myMap.insert(std::make_pair(Node("abc",18), 16));
return 0;
}
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include "stdafx.h"
#include <iostream>
#include <unordered_map>
#include <string>
#include<vector>
#include<string>
#include <bitset>
#include <utility>
#include <fstream>
using namespace std;
class FilterKeys
{
public:
FilterKeys(string a, int b)
{
name = a;
time = b;
}
string name;
int time;
};
class HashKey
{
public:
size_t operator() (FilterKeys const& key) const
{
return std::hash<std::string>()(key.name) ^
(std::hash<int>()(key.time) << 1);
}
};
class EqualTo
{
public :
bool operator()(const FilterKeys& lhs, const FilterKeys& rhs) const
{
return lhs.name == rhs.name && lhs.time == rhs.time;
}
};
class Init {
unordered_multimap<FilterKeys, int, HashKey, EqualTo> _myMap;
public:
void filterng_three_addId_on_location_and_time(ifstream file)
{
string location;
int time, addId;
if (!file)
cerr << "Cant open " << endl;
while (file >> location >> time >> addId)
{
if (_myMap.count(FilterKeys(location, time)) < 3)
_myMap.insert(std::make_pair(FilterKeys(location, time), addId));
}
}
unordered_multimap<FilterKeys, int, HashKey, EqualTo> getHashMap()
{
return _myMap;
}
};
The error is telling you that you can't call the copy constructor of ifstream - it doesn't have one.
You need to change:
void filterng_three_addId_on_location_and_time(ifstream file)
to
void filterng_three_addId_on_location_and_time(ifstream& file)
This will mean that you pass a reference to the file object (rather than a copy). You need to be aware that passing a reference means that changes you make in the called function will be seen in main.
In other cases, you may want to pass a reference, but forbid the called function from making changes to the object. In that case you would write:
void filterng_three_addId_on_location_and_time(const ifstream& file)
(a reference to const). That won't work here, because all the input functions modify the ifstream object, so you would get a compiler error when you called them.

C++ Class object as argument in other class function

I have a C++ project in Visual Studio 2015.
GameManager.h and Input.h both give me a syntax error: identifier 'Player'. This happens because I want to give an object of type 'Player' as an argument to functions in these two Header files and their appropriate C++ Files.
How do I fix that? For further information I have provided my code.
main.cpp:
#include "GameManager.h"
#include "Input.h"
#include "Player"
#include <iostream>
#include <string>
using namespace std;
const int maxPlayerCnt = 10;
static Player p1, p2, morePlayers[maxPlayerCnt];
int main()
{
GameManager game;
game.Game(p1, p2, morePlayers);
return 0;
}
It creates an object of type GameManager and 3 objects of type Player.
GameManager.h:
#include "Player.h"
class GameManager
{
public:
void Game(Player p1, Player p2, Player morePlayers[]);
};
GameManager.cpp:
#include "GameManager.h"
void GameManager::Game(Player p1, Player p2, Player morePlayers[])
{
int playerCnt = 0;
Input input;
input.getPlayerDetails(playerCnt, p2);
input.getMorePlayerDetails(playerCnt, morePlayers);
}
It creates an object of type Input to use further functions and will get more code, once I figure this problem out. And then calls to functions with specific arguments it gets from main.cpp
Input.h:
#pragma once
#include "Player.h"
#include <iostream>
#include <string>
using namespace std;
class Input
{
public:
Input();
void getPlayerDetails(int &playerNum, Player p);
void getMorePlayerDetails(int &playerNum, Player p[]);
};
It includes everything Input.cpp needs and initializes the funcitons
Input.cpp:
#include "Input.h"
void Input::getPlayerDetails(int &playerNum, Player p)
{
playerNum++;
string currentName;
char currentSymbol;
cout << "Player " << playerNum << ", what is your name?\n";
cin >> currentName;
p.setName(currentName);
cout << currentName << " what is your symbol?\n";
cin >> currentSymbol;
p.setSymbol(currentSymbol);
}
void Input::getMorePlayerDetails(int &playerNum, Player p[])
{
int plNum = playerNum;
if (playerNum >= 12)
cout << "You can't get another player!\n";
else
{
//getPlayerDetails(p[playerNum - 2], (plNum - 2));
}
}
It for now has all the functions needed and both get an object of type Player. And the second function is not quite done now. But that is not important.
Player.h:
#pragma once
#include <iostream>
#include <string>
using namespace std;
class Player
{
private:
string _name;
char _symbol;
public:
Player();
void getName();
void setName(string name);
void setSymbol(char symbol);
};
Player.cpp:
#include "Player.h"
Player::Player()
{
}
void Player::getName()
{
cout << "I have no name!\n";
}
void Player::setName(string name)
{
_name = name;
}
void Player::setSymbol(char symbol)
{
_symbol = symbol;
}
If you can help me, I would be pleased to see your response.

Trouble accessing members of class from a separate class C++

I am having a lot of trouble with a relatively simple task. I have two header files, input.h and grains.h, both of which have classes defined within them. I have included all header and source files for this project below.
My problem is that when input->from_file(fname) is executed, the value printed to the screen is correct, let's say it is 4. Then when it moves on the grains->get_pars(), the value printed to the screen is garbage, usually ~605937280. I know this type of garbage value is indicative of the variable not being set, but I don't understand how it is not being set.
My goal is to have input.cpp read some file for some parameters, which are important to grains.cpp, and pass them along. I thought that derived classes would do the trick, but something is not working right. Any hints on what I have done wrong would be greatly appreciated. Also, any suggestions to achieve this goal aside from the one I have presented are very welcome, thanks. Note, the code as shown compiles just fine.
//input.h
#ifndef Input_H
#define Input_H
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <cstring>
class Input {
protected:
int in_grains;
public:
void from_file(std::string);
};
#endif
//grains.h
#ifndef Grains_H
#define Grains_H
#include "input.h"
class Grains : protected Input {
protected:
int grains;
public:
void get_pars(void);
};
#endif
//input.cpp
#include "input.h"
void Input::from_file(std::string infile)
{
std::ifstream input(infile.c_str());
std::istringstream iss;
std::string line, keyword;
char arg1[50], arg2[50], arg3[50];
while(std::getline(input,line)) {
iss.clear();
iss.str(line);
iss >> keyword >> arg1 >> arg2 >> arg3;
if ((keyword == "GRAINS") || (keyword == "Grains") || (keyword == "grains")) {
this->in_grains = atoi(arg1);
}
}
fprintf(stdout,"%i\n",in_grains );
}
//grains.cpp
#include "grains.h"
void Grains::get_pars(void)
{
this->grains = in_grains;
fprintf(stdout,"%i\n",grains );
}
//main.cpp
#include "input.h"
#include "grains.h"
int main(int nargs, char *argv[])
{
Input obj1;
Input *input = &obj1;
Grains obj2;
Grains *grains = &obj2;
std::string fname = argv[1];
input->from_file(fname.c_str());
grains->get_pars();
return 0;
}
I am guessing that when you execute:
input->from_file(fname.c_str());
grains->get_pars();
you are expecting the in_grains from input to be available as grains->grains. input and grains are two different objects. in_grains has not been set on the object grains points to.
Perhaps you meant to use:
int main(int nargs, char *argv[])
{
Grains obj;
Input *input = &obj;
Grains *grains = &obj;
std::string fname = argv[1];
input->from_file(fname.c_str());
grains->get_pars();
return 0;
}
However, to use that, you have to make Input a public base class of Grain, not a protected base class.
class Grains : public Input {

Why is my array undefined in main when the class headers are included?

So here is the main where i'm trying to call the array by a pointer:
#include <iostream>
#include "Lottery.h"
#include "Player.h"
#include "LotteryData.h"
using namespace std;
int main()
{
Player player;
Lottery random;
LotteryData data;
player.Input();
random.setRandomNumber();
data.PassInfo(int (&Numbers)[6][6]);
}
Apparently "Numbers" is undefined even though the header is included, here's the header and .cpp files relating to it.
LotteryData.h
#pragma once
#include <iostream>
#include <fstream>
#include "Lottery.h"
#include "Player.h"
using namespace std;
class LotteryData
{
private:
public:
LotteryData();
~LotteryData();
void PassInfo(int (&Numbers)[6][6]);
};
LotteryData.cpp
#include <iostream>
#include <fstream>
#include "LotteryData.h"
using namespace std;
LotteryData::LotteryData()
{
}
LotteryData::~LotteryData()
{
}
void LotteryData::PassInfo(int (&Numbers)[6][6])
{
int* ptr;
FILE *Numfile;
Numfile = fopen("C:/Num.txt", "wb");
ptr = &Numbers[6][6];
for (int i=0; i<36; i++)
{
fwrite(ptr, sizeof(int), 36*36, Numfile);
}
fclose(Numfile);
//ofstream out("Numbers.txt");
}
Everything seems fine, I'm puzzled why the reference in the main says the array is undefined, any ideas?
edit: Apologies, missed some bits
Player.h
#pragma once
#include <iostream>
#include <fstream>
using namespace std;
class Player
{
private:
public:
Player();
~Player();
void Input();
int Numbers[6][6];
};
Player.cpp
#include <iostream>
#include <fstream>
#include "Player.h"
using namespace std;
Player::Player()
{
}
Player::~Player()
{
}
void Player::Input()
{
int num(0);
int duplicate = 0;
int game = 0;
int NumberofGames = 0;
cout<<"How many games do you want to play for this weeks draw?"<<endl;
cin>>NumberofGames;
if (NumberofGames>6)
{
cout<<"Please enter an amount between 1 and 6"<<endl;
cin>>NumberofGames;
}
do
{
for (int i=0;i<6;i++)
{
cout<<"Enter Number "<< (i+1) <<endl;
cin>>num;
if (num > 0 && num <67)
{
Numbers[game][i]= num;
}
else
{
cout <<"Please enter number between 1 and 66"<<endl;
i = i-1;
}
}
game = game + 1;
NumberofGames = NumberofGames - 1;
}
while (NumberofGames=0);
}
void PassInfo(int (&Numbers)[6][6]);
That line does not declare an array - it declares a function. You have no declaration for an array in your class (in fact, you have no data members declared in your class at all).
If you want to declare a member array, you need to modify your class definition:
class LotteryData
{
private:
int Numbers[6][6]; // this declares an array
public:
LotteryData();
~LotteryData();
void PassInfo(int (&arr)[6][6]); // this is still a function declaration
};
Just because you made a function's parameter be named Numbers doesn't magically mean that your program has an array called Numbers declared in it.
So a Player has an array called "Numbers".
Then you would use it like this:
data.PassInfo(player.Numbers);
In your main() function,
data.PassInfo(int (&Numbers)[6][6]);
This is wrong. You should simply pass a reference to 2D array.
int (&Numbers)[6][6];
data.PassInfo(Numbers);