Trouble accessing members of class from a separate class C++ - 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 {

Related

Serialize a c++ virtual class without boost?

I want to dump some data into files, then load it back. i do care the performance.
I don't want to use boost serialization. I want to serialize and load it back by myself.
if the struct is POD, i think this will be quite easy, but there is some problems if my data class has virtual function, like this:
// base.h
#include <string>
class Base {
public:
virtual std::string show_string() = 0;
int b;
};
class A : public Base {
public:
std::string show_string() override { return "this is A"; } // here is the problem, virtual pointer
int a;
};
there is a data producer, dump the data into file, like this:
#include <fstream>
#include <iostream>
#include "./base.h"
using namespace std;
int main() {
std::fstream f;
f.open("a.bin", std::ios::out | std::ios::binary);
for (int i = 0; i < 10; ++i) {
A a;
a.a = i;
a.b = i - 1;
f.write((char*)&a, sizeof(a));
}
f.close();
}
then i need to load it back, my code looks like:
#include "./base.h"
#include <fstream>
#include <iostream>
using namespace std;
int main() {
std::fstream f;
f.open("a.bin", std::ios::in | std::ios::binary);
char buff[65536];
f.read(buff, sizeof(buff));
A* a = (A*)buff;
cout << a->show_string() << endl;
f.close();
}
this will crashed, i think the problem is the virtual pointer.
for virtual pointer, i think i need a correct serialize method.
could you help on this? how can i make this work?

anyone know how to initialize an empty array

Anyone know how to Initialise the array of car registration structures by placing a “Empty” in the car registration number of each array element.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <conio.h>
#include <iomanip>
using namespace std;
int main()
{
struct car;
{
string car_reg = 0;
char car_manuf[30];
char car_model[30];
double price;
string car_reg{};
}
}
need some h3elp
Explanation inline.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <conio.h>
#include <iomanip>
using namespace std;
int main()
{
struct car // removed ; the ; terminates the definition, cutting it off
// and leaving you with a declaration. Everything in the braces
// that follow would be seen as a block of code defining two
// automatic variables scoped inside the block. Useless in this
// case.
{
string car_reg = 0; // this is actually NASTY! More on it later
char car_manuf[30] = "EMPTY"; // assigns default value. But only if your
// compiler comes from this decade.
// If you are rocking an antique you can't
// do this. Will cover what you can do below.
char car_model[30] = "EMPTY";
string car_reg{}; // cannot reuse the car_reg identifier in the same scope
// car_reg is either a variable or a function.
}; // ; goes here
car c; // for testing purposes
cout << c.car_manuf << ',' << c.car_model; // for testing
}
string car_reg = 0; is nasty. What it does is defines a member variable car_reg and uses 0 as the default. The 0 is converted to a null pointer to a char array. The string constructor attempts to initialize from a null pointer and blows up at runtime. The compiler is just fine with this bit of stupidity because in the old days NULL could be #define NULL 0 and we don't want to break decades of old code by fixing this problem.
Since we can't do default initializations in pre C++11 code we need a constructor to do the work. Yup. structs can have constructors. This is because a struct and a class are almost identical. The only difference you're ever likely to see between the two is class defaults to private access and structs default to public access.
struct car
{
char car_manuf[30];
char car_model[30];
car (): car_manuf("EMPTY"), car_model("EMPTY")
{
}
};
Note that his isn't as groovy as it looks. You're usually better off with something like
struct car
{
string car_manuf;
string car_model;
car (const string & manuf,
const string & model): car_manuf(manuf), car_model(model)
{
}
};
and not allowing the empty case at all. When possible force users to initialize a class into a fully initialized state. And use std::string. Very handy tool, std::string.
Note that
struct car
{
char car_manuf[30];
char car_model[30];
car (const char * manuf,
const char * model):
car_manuf(manuf), car_model(model) // fails to compile
{
}
};
is not possible. You can't initialize a char array with a pointer to char. I'm not entirely certain why the language doesn't have a rule to handle this, but it doesn't. If forced to use char arrays,
struct car
{
char car_manuf[30];
char car_model[30];
car (const char * manuf,
const char * model)
{
strcpy(car_manuf, manuf);
strcpy(car_model, model);
}
};
and make dang sure that manuf and model will fit in 29 characters or less.
Have you tried a simple for loop, to fill (for example) the char_model array with zeros?
....
char car_model[30];
/* Adding the for loop here (it will fill car_model's elements with zeros*/
for(int i=0; i<=sizeof(car_model); i++){
car_model[i]=0;
....
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <conio.h>
#include <iomanip>
using namespace std;
int main()
{
struct car
{
string car_reg = {"Empty"};
char car_manuf[30];
char car_model[30];
car(const char* manuf,
const char* model)
{
strcpy(car_manuf, manuf);
strcpy(car_model, model);
}
};
}

C++ managing ifstream in a container with different object types

I have created several different objects of Dog and Cat inside the container animalColl. I am trying to workout how to adjust the file stream that is read so that if the object in the container is Cat then the catfile is used and Dog uses the dogfile. Currently, only the animalType passed into the parameter is used. Is it possible to choose which file stream is used based on the object type?
void Animal::load(std::string animalType)
{
std::string file = animalType + ".csv";
std::ifstream lstream(file);
for (Animal *a : animalColl)
{
a->load(lstream); //uses one stream to read all the different objects in container
}
}
Unfortunately, I'm not sure why you're calling load recursively, so I can't give an exact answer. I think the answer you're looking for is going to be using polymorphism. This is a basic example:
animal.h
#ifndef ANIMAL_H
#define ANIMAL_H
#include <iostream>
#include <string>
class Animal
{
public:
void load()
{
std::string fileName = this->getAnimalFilename() + ".csv";
std::cout << "fileName = " << fileName << std::endl;
}
protected:
virtual std::string getAnimalFilename() { return "Animal"; }
};
#endif //ANIMAL_H
dog.h
#ifndef DOG_H
#define DOG_H
#include <string>
#include <iostream>
class Dog : public Animal
{
protected:
virtual std::string getAnimalFilename() { return "Dog"; }
};
#endif //DOG_H
cat.h
#ifndef CAT_H
#define CAT_H
#include <iostream>
#include <string>
class Cat : public Animal
{
protected:
virtual std::string getAnimalFilename() { return "Cat"; }
};
#endif //CAT_H
And an example usage (note that you MUST use a pointer to the base class to get the overriding feature of polymorphism, and you MUST declare a function as virtual to override it in the derived class).
EDIT: The below main.cpp was edited to use smart pointers because it used raw pointers and caused a memory leak, pointed out by #ArchbishopOfBanterbury.
main.cpp
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include "animal.h"
#include "dog.h"
#include "cat.h"
int main(int argc, char *argv[])
{
std::vector<std::unique_ptr<Animal>> animalColl;
animalColl.emplace_back(new Dog());
animalColl.emplace_back(new Cat());
animalColl.emplace_back(new Cat());
animalColl.emplace_back(new Dog());
for (auto &a : animalColl) {
a->load();
}
return 0;
}
And the output:
fileName = Dog.csv
fileName = Cat.csv
fileName = Cat.csv
fileName = Dog.csv
The basic idea is that you use the keyword virtual to override the behavior when using a pointer to the base class. So in my example, getAnimalFilename is overrided in the Dog and Cat class to return the correct string, rather than passing it into the load() function. Does that help any? Go ahead and reply to this comment and I'll try to help as much as I can.
There are a few ways you could do this. You could add an element to the class called name and strcmp this to check for type for instance:
struct Animal {
};
struct Dog : Animal {
string name = "Dog";
};
struct Cat : Animal {
string name = "Cat";
};
int main() {
Dog d;
if("Dog" == d.name) {
//do something
}
else if("Cat" == d.name) {
//do something else
}
}
Another way to do this would be if you know the type of another object, or are willing to create another object of type Dog or Cat, you can compare those types using typeid(obj) for instance, using the same structs as above:
int main(int argc, const char * argv[]) {
Dog d, o;
if (typeid(d) == typeid(o)) {
//do something
}
else {
//do something else
}
}

Redefinition of class

I got three .cpp files and two header files.
But when i compile them, meaning the Point.cpp, Data.cpp and main.cpp, it will say
Data.h:6:7 redefinition of Data at 'Data.h'
Data.h:6:7 previously definition of 'class Data'
Below is my Data.h(previously known as 2.h at above)
#include <iostream>
#include <string>
using namespace std;
class Data
{
private:
string sType;
public:
Data();
Data(string);
void setSType(string);
string getSType();
};
Below is my data.cpp
#include "Data.h"
Data::Data()
{
sType = "";
}
Data::Data(string s)
{
sType = s;
}
void Data::setSType(string ss)
{
sType = ss;
}
string Data::getSType()
{
return sType;
}
Below is my PointD.h (previously known as 3.h)
#include <iostream>
#include <string>
#include "Data.h"
using namespace std;
class PointD
{
private:
int x
Data data1;
public:
PointD();
PointD(int,Data);
void setX(int);
void setData(Data);
int getX();
Data getData();
};
Below is my PointD.cpp
#include "PointD.h"
PointD::PointD()
{
x = 0;
}
PointD::PointD(int xOrdinate,Data dd)
{
x = xOrdinate;
data1 = dd;
}
void PointD::setXordinate(int Xordinate)
{
x = Xordinate;
}
void PointD::setData(Data dd)
{
data1 = dd;
};
int PointD::getXordinate()
{
return x;
}
Data PointD::getData()
{
return data1;
}
This is my main.cpp
#include <iostream>
#include <string>
#include "Data.h"
#include "PointD.h"
using namespace std;
int main()
{
const int MAX_NUM = 20;
Data ldata[MAX_NUM];
PointD pointd[MAX_NUM];
//more codes..
}
But when i compile them, meaning the Point.cpp, Data.cpp and main.cpp, it will say
Data.h:6:7 redefinition of Data at 'Data.h'
Data.h:6:7 previously definition of 'class Data'
Can anybody let me know whats actually went wrong here..
You need to use include guards, or the easiest:
#pragma once
in your header files
See Purpose of Header guards for more background
Idea: 1.hpp
#ifndef HEADER_GUARD_H1_HPP__
#define HEADER_GUARD_H1_HPP__
// proceed to declare ClassOne
#endif // HEADER_GUARD_H1_HPP__
In each of your header files write:
#ifndef MYHEADERNAME_H
#define MYHEADERNAME_H
code goes here....
#endif
Its better like this:
#ifndef DATA_H /* Added */
#define DATA_H /* Added */
#include <iostream>
#include <string>
// using namespace std; /* Removed */
class Data
{
private:
std::string sType;
public:
Data();
Data( std::string const& ); // Prevent copy of string object.
void setSType( std::string& ); // Prevent copy of string object.
std::string const& getSType() const; // prevent copy on return
std::string& getSType(); // prevent copy on return
};
#endif /* DATA_H */
The big fix is adding ifndef,define,endif. The #include directive works as if copying and pasting the .h to that line. In your case the include from main.cpp are:
main.cpp
-> Data.h (1)
-> Point.h
-> Data.h (2)
At (2), Data.h has already been `pasted' into main.cpp at (1). The class declaration of Data, i.e. "class Data{ .... };" , appears twice. This is an error.
Adding include guards to the top and bottom of every .h are standard practice to avoid this problem. Don't think about it. Just do it.
Another change I'd suggest is to remove any "using namespace ..." lines from any .h . This breaks the purpose of namespaces, which is to place names into separate groups so that they are not ambiguous in cases where someone else wants an object or function with the same name. This is not an error in your program, but is an error waiting to happen.
For example, if we have:
xstring.h:
namespace xnames
{
class string
{
...
};
}
Foo.h
#include <xstring>
using namespace xnames;
...
test.cxx:
#include "Foo.h"
#include "Data.h" // Breaks at: Data( string ); -- std::string or xnames::string?
...
void test()
{
string x; // Breaks. // std::string or xnames::string?
}
Here the compiler no longer knows whether you mean xnames::string or std::string. This fails in test.cxx, which is fixable by being more specific:
void test()
{
std::string x;
}
However, this compilation still now breaks in Data.h. Therefore, if you provide that header file to someone, there will be cases when it is incompatible with their code and only fixable by changing your header files and removing the "using namespace ...;" lines.
Again, this is just good coding style. Don't think about it. Just do it.
Also, in my version of Data.h, I've changed the method parameters and return types to be references (with the &). This prevents the object and all of its state from being copied. Some clever-clogs will point our that the string class's is implementation prevents this by being copy-on-write. Maybe so, but in general, use references when passing or returning objects. It just better coding style. Get in the habit of doing it.

Variable scope error when declaring friend function

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.