I'm trying to implement a LinkedQueue Structure in c++ to store the data of some flights.
So, first of all I have to read a csv file, what provides the data to store.
The LinkedQueue must work this way: the atributes of each Flight has to be stored using the Flight class, and then the LinkedQueue must have a specific nodes called FlightNode to finally store flights.
My code isn't compiling because i can't implement the getNext() function in a correct way.
I'm giving my code below with the implementation of each class. If you guys can make any suggestion it will be very helpfull.
Thank you a lot!!
This is my header class for Flight.h:
class Flight {
public:
Flight();
virtual ~Flight();
string getID();
void setID(string new_id);
string getOrigen();
void setOrigen(string new_origen);
string getDesti();
void setDesti(string new_desti);
string getHora();
void setHora(string new_hora);
private:
string id;
string origen;
string desti;
string hora_sortida;
};
Flight.cpp:
Flight::Flight() {
}
Flight::~Flight() {
}
string Flight::getID(){
return id;
}
string Flight::getOrigen(){
return origen;
}
string Flight::getDesti(){
return desti;
}
string Flight::getHora(){
return hora_sortida;
}
void Flight::setID(string new_id){
id = new_id;
}
void Flight::setOrigen(string new_origen){
origen = new_origen;
}
void Flight::setDesti(string new_desti){
desti = new_desti;
}
void Flight::setHora(string new_hora){
hora_sortida = new_hora;
}
FlightNode.h:
class FlightNode {
public:
FlightNode(Flight& f);
FlightNode(const FlightNode& orig);
virtual ~FlightNode();
FlightNode* getNext();
void setNext(FlightNode* n);
Flight& getElement();
private:
Flight* _element;
FlightNode* _next;
};
FlightNode.cpp:
FlightNode::FlightNode(Flight& f) {
this->_element = &f;
this->_next = nullptr;
}
FlightNode::FlightNode(const FlightNode& orig) {
}
FlightNode::~FlightNode() {
}
FlightNode* FlightNode::getNext(){
return this->_next;
}
void FlightNode::setNext(FlightNode* n){
this->_next = n;
}
Flight& FlightNode::getElement(){
//Don't know how to implement this one, because I declared _element as a pointer but what I need here is to return a reference.
}
main.cpp:
string id;
string origen;
string desti;
string hora;
fstream fin;
fin.open("flights.csv", ios::in);
string line, word;
string id, origen, desti, hora;
while (getline(fin, line)) {
stringstream in(line);
Flight* new_flight = new Flight;
for (int i = 0; getline(in, word, ','); ++i) {
switch (i) {
case 0:
new_flight->setID(word);
break;
case 1:
new_flight->setOrigen(word);
break;
case 2:
new_flight->setDesti(word);
break;
case 3:
new_flight->setHora(word);
break;
}
}
cout << "id:" << new_flight->getID() << " origen:" << new_flight->getOrigen() << " desti: " << new_flight->getDesti() << endl;
queue.enqueue(*new_flight);
}
You can just return the reference behind the pointer:
return *_element;
However, if you plan to do so please ensure that the pointer is not null at the time of the above dereference.
Related
I have class Pstring
class Pstring
{
private:
string palindrome;
public:
Pstring() { palindrome = ""; }
Pstring(string pal) { setString(pal); }
void setString(string pal) { palindrome = pal; }
string getPal() const { return palindrome; }
};
an object in my main method Pstring palindrome(palin) defined by
string palin = "";
cout << "Enter a palindrome:\n";
getline(cin, palin);
Pstring palindrome(palin);
and a current test method bool isPalindrome(string pal)defined as
bool isPalindrome(string pal)
{
bool flag;
cout << "Do I have access to this?";
cout << pal;
//code goes here to check for palindrome, return bool
}
I want to have my Pstring class object palindrome use the method isPalindrome in main, but when I try and invoke the method by using palindrome.isPalinedrome(palin); it doesn't seem to have access to the method.
What can I do to allow a method outside the class to be used by a class object in main?
You don't have a isPalinedrome() method defined in the Pstring class, so you can't call it as palindrome.isPalinedrome() in your main code.
Instead of having Pstring try to call a function in your main code, you should move the palindrome logic into Pstring, and then the main code can ask Pstring when needed.
Try this:
class Pstring
{
private:
string value;
public:
Pstring() { }
Pstring(const string &s) { setString(s); }
void setString(const string &s) { value = s; }
string getString() const { return value; }
// add this...
bool isPalindrome() const {
//code goes here to check value for palindrome, return bool
}
};
Then your main code can do this:
bool isPalindrome(const string &value)
{
Pstring palindrome(value);
return palindrome.isPalindrome();
// or simply:
// return Pstring(value).isPalindrome();
}
int main()
{
string palin;
cout << "Enter a palindrome:\n";
getline(cin, palin);
if (isPalindrome(palin)) {
// do something ...
} else {
// do something else...
}
return 0;
}
Or this:
int main()
{
string palin;
cout << "Enter a palindrome:\n";
getline(cin, palin);
Pstring palindrome(palin);
if (palindrome.isPalindrome()) {
// do something ...
} else {
// do something else...
}
return 0;
}
You should add your test method into the class:
class Pstring
{
private:
string palindrome;
public:
// you don't need to initialize palindrome = "" (it's initialized by default)
Pstring() {}
// always pass strings as const reference unless you have
// special reason to do it another way...
Pstring(const string& pal) { setString(pal); }
void setString(const string& pal) { palindrome = pal; }
string getPal() const { return palindrome; }
bool isPalindrome() const // you don't have to pass string
{
bool flag;
cout << "Do I have access to this?";
cout << palindrome; // please note this
//code goes here to check for palindrome, return bool
}
};
And also please note the typo:
palindrome.isPalinedrome(palin);
You can use function pointer to implement it:
declare class:
class Pstring{
private:
string palindrome;
public:
Pstring() { palindrome = ""; }
Pstring(string pal) { setString(pal); }
void setString(string pal) { palindrome = pal; }
string getPal() const { return palindrome; }
//add a function pointer member:
bool(*isPalindrome) (string);
};
then define function:
bool isPalindrome(string pal)
{
bool flag;
cout << "Do I have access to this?";
cout << pal;
//code goes here to check for palindrome, return bool
return true;
}
now you can write code in main function:
string palin = "";
cout << "Enter a palindrome:\n";
getline(cin, palin);
Pstring palindrome(palin);
palindrome.isPalindrome = isPalindrome;//bind function
you can use the function by the object now:
palindrome.isPalindrome(palin);
Sorry. what's the point to create this class? the only thing you need is the helper function isPalindrome(const std::string&). If you need some kinda scope protection, put it into a namespace may look better
Sorry but I have to say you are just make things complicated.
C++ is not java. If you don't use it, you should not pay for it.
i am dealing with large dataset. May i ask you how it is possible to store strings in the classes i want to use with stxxl? I have read several discussions and everywhere was said that string is not POD type therefore it cannot be stored in the stxxl::vector, but i am not sure,because i tried it and i checked the data and everything seems to be fine. i have also saw an approach here https://github.com/Project-OSRM/osrm-backend/blob/725b93a961625a7b04d54806d7e0f80252a6bcd0/extractor/extraction_containers.hpp and they use stxxl::vector, so maybe the library got updated to support std::string?
class HighWay
{
private:
uint64_t id;
string name;
int speed;
string attributes; //additional attributes of way
string edges; //written uint64_t from,uint64_t to, int distance written as string
string nodes; //vector<uint64_t> written as string
public:
HighWay() = default;
void setId(uint64_t _id) {
id = boost::lexical_cast<string>(_id);
}
void setName(string _name) {
name = _name;
}
void setSpeed(int _speed) {
speed = _speed;
}
void setAttributes(string _attributes) {
attributes = _attributes;
}
void setEdges(string _edges) {
edges = _edges;
}
void setNodes(vector<uint64_t>refs) {
stringstream s;
uint64_t i = 0;
for (; i < refs.size()-1;i++) {
s << boost::lexical_cast<uint64_t>(refs[i]) << " ";
}
s << boost::lexical_cast<uint64_t>(refs[i]);
nodes = s.str();
}
uint64_t getId() {
return id;
}
string getName() {
return name;
}
int getSpeed() {
return speed;
}
string getAttributes() {
return attributes;
}
string getEdges() {
return edges;
}
std::vector<int64_t> getNodes() {
stringstream s(nodes);
uint64_t node;
std::vector<int64_t> result;
while (s >> node) {
result.push_back(static_cast<int64_t>(node));
}
return result;
}
};
I have also created code which stores the strings as POD,storing the string in vector of char and in map remembering lower and upper bound index in the array. But this approach leads to many std::maps used in the application.
//class to store in map
struct TypeName{
uint64_t start;
uint64_t end;
};
std::istream& operator >> (std::istream& i, TypeName& entry)
{
i >> entry.start;
i >> entry.end;
return i;
}
std::ostream& operator << (std::ostream& i, const TypeName& entry)
{
i << entry.start << " ";
i << entry.end;
return i;
}
struct PoiCategories{
uint64_t start;
uint64_t end;
};
std::istream& operator >> (std::istream& i,PoiCategories& entry)
{
i >> entry.start;
i >> entry.end;
return i;
}
std::ostream& operator << (std::ostream& i, const PoiCategories& entry)
{
i << entry.start << " ";
i << entry.end;
return i;
}
//object i want to store
struct Poi {
Poi() = default;
uint64_t id;
char type;
uint64_t id_in_pois; //id in vector pois
void addCategories(
vector<int> &kats, //categories to insert
stxxl::vector<uint64_t> &categories, //vector to store category
std::unordered_map <uint64_t, PoiCategories> &idPoi_categories //index to vector categories to retrieve all categories for Poi
)
{
size_t start = categories.size();
for (auto & kat : kats) {
categories.push_back(kat);
}
size_t end = categories.size() - 1;
idPoi_categories.insert(make_pair(id, PoiCategories{start, end }));
}
vector<int> getCategories(
stxxl::vector<uint64_t> &categories,
std::unordered_map <uint64_t, PoiKategorie> &idPoi_categories
)
{
std::vector<int> result;
PoiCategories bounds = idPoi_categories.find(id)->second;
for (size_t i = bounds.start; i <= bounds.end; i++) {
result.push_back(categories[i]);
}
return result;
}
};
Problem in my application is that i am storing a few string data, which are mainly names of streets and POIs. Maybe i am using wrong library. If so,can you recommend me a better approach to store data while preprocessing?
It's indeed banned, but the symptoms of violating the no-POD rule are generally unpredictable. It may very well appear to work as long as the strings all fit in memory, but in that case you didn't need the STXXL anyway.
My code:
class item{
int plu;
char * name;
double price;
double inv;
public:
void setPLU(int g) { plu = g; }
void setName(const char * p) { name = copyStr(p); }
void setPrice(double g) { price = g; }
void setInventory(double g) { inv = g; }
int getPlu() { return plu; }
char*getName() { return name; }
double getPrice() { return price; }
double getInventory() { return inv; }
item(){
name = nullptr;
}
~item(){
delete name;
}
};
class puItem : public item{
bool type;
public:
void setType(bool g) { type = g; }
bool getType() { return type; }
};
class nodeU{
puItem fruit;
nodeU * next;
public:
nodeU * getNext(){ return next; }
puItem getFruit(){ return fruit; }
void setNext(nodeU * g){ next = g; }
void setFruit(puItem g) { fruit = g; }
nodeU(){
next = nullptr;
}
};
class linkedListU{
nodeU * head;
int size;
public:
nodeU * getHead(){
return head;
}
void setHead(nodeU * n){
head = n;
}
//Append
void appendNode(nodeU * n){
if (head == nullptr){
head = n;
}
else{
nodeU * iter = head;
while (iter){
iter = iter->getNext();
}
iter->setNext(n);
}
size++;
}
linkedListU()
{
head = nullptr;
size = 0;
}
puItem * pluLookup(int g){
nodeU * iter = head;
while (iter)
{
if ((iter->getFruit()).getPlu() == g)
return &(iter->getFruit());
iter = iter->getNext();
}
return nullptr;
}
};
void checkout(linkedListP, linkedListU);
linkedListU unitList;
linkedListP poundList;
nodeU * inputU=new nodeU;
int main()
{
ifstream infile;
ofstream outfile;
int tempPlu;
string tempName;
bool tempType;
double tempPrice, tempInv;
infile.open("products.txt");
puItem unit;
infile >> tempPlu;
if (!infile.good())
{
infile.clear();
infile.ignore();
}
infile >> tempName;
if (!infile.good())
{
infile.clear();
infile.ignore();
}
infile >> tempType;
if (!infile.good())
{
infile.clear();
infile.ignore();
}
infile >> tempPrice;
if (!infile.good())
{
infile.clear();
infile.ignore();
}
infile >> tempInv;
if (!infile.good())
{
infile.clear();
infile.ignore();
}
if (tempType == 0){
unit.setInventory(tempInv);
unit.setName(tempName.c_str());
unit.setPLU(tempPlu);
unit.setType(tempType);
unit.setPrice(tempPrice);
inputU->setFruit(unit);
unitList.appendNode(inputU);
}
checkout(poundList, unitList);
system("pause");
return 0;
}
void checkout(linkedListU p){
int key = -10;
puItem * searchU=nullptr;
int counter = 0;
double total = 0;
double amount;
cout << "Enter the plu for the item you want or enter 0 to exit: ";
cin >> key;
while (key < 0)
{
cout << "\nInvalid input please re enter: ";
cin >> k
searchU = p.pluLookup(key);
}
while (key)
{
When it gets to the plu lookup it throws the error and I cant seem to find out why.
I know that that is error is for deleting something twice but I couldnt find any instance of that in this code.
There are a lot of issues with your code, where most of them are due to your classes not being safely copyable (they lack a user-defined copy constructor and assignment operator, and destructor). Please see the rule of 3:
What is The Rule of Three?
Your checkout function has the following prototype:
void checkout(linkedListU p){
This means that you are passing linkedListU by value. Since linkedListU failed to follow the rule of 3, when you pass this type by value, you will invoke the compiler-defined copy constructor which only makes shallow copies, thus causing undefined behavior.
Your linked list class has members that are pointers to dynamically allocated memory, and they need to be properly handled by following the Rule of 3 at the link above. Since you failed to do that, passing by value cannot be done safely.
To address this issue, you can pass the linked list by reference, not by value:
void checkout(linkedListU& p){
This will stop the copying to occur, but it really doesn't address the underlying issue of the rule of 3 not being used in any of your classes.
For example, your puItem is being returned by value in the puItem::getFruit function, and also passed by value in the puItem::setFruit function. Calling these functions without any changes also invokes undefined behavior due to these classes not being safely copyable (also due to you using members that point to dynamically allocated memory).
To address this issue, the first thing you can do is change the base class item to use std::string name; instead of char *name;. This makes item now a copyable class without having to write user-defined copy operations or to have a destructor that needs to delete name;. The reason is that once std::string is used, all of your members in item can be copied without user intervention. The compiler default version would suffice.
class item
{
int plu;
std::string name;
double price;
double inv;
public:
void setPLU(int g) { plu = g; }
void setName(const char * p) { name = p; }
void setPrice(double g) { price = g; }
void setInventory(double g) { inv = g; }
int getPlu() { return plu; }
std::string getName() { return name; }
double getPrice() { return price; }
double getInventory() { return inv; }
};
Note that there is no need for a destructor. Now, when puItem is derived from this class, puItem is also now safely copyable, and you can pass and return puItem by value:
class puItem : public item
{
bool type;
public:
void setType(bool g) { type = g; }
bool getType() { return type; }
};
Making these changes totally eliminates usage of these classes from causing heap errors, double deletion errors, or memory leaks. Any further errors concerning memory issues are now focused on your linked list class (which uses dynamically allocated memory). So the least, the problem is narrowed down by a huge amount and is now focused.
class test
{
private:
string *firstname;
public:
void setfname(const string fname[])
{
delete[] firstname;
firstname = new string[3];
for (int i = 0; i < 3; i++)
{
firstname[i] = fname[i];
}
}
string* getfname(const string fname[]) const
{
return firstname;
}
};
ok now I know the return function is wrong because it's giving me direct access, how do i set up the function so it doesn't allow it.
This is how I am going to test it:
int main()
{
test t;
string narray[3] = { "Name1", "Name2", "Name3" };
t.setfname(narray);
cout << "\nAfter t.setfname(narray);"
<< "\nf.getfname(narray) follows: ";
cout << t.getfname(narray);
}
I know getfname is wrong, how do I fix it?
In the simplest case, just return a copy of the string instead of a pointer:
string getfname(const string fname[]) const
{
return *firstname;
}
Even better, store a string instead of a pointer to it:
class test
{
private:
string firstname;
...
i have this class
class Dados
{
string name;
int valor;
public:
Dados(string n, int v) : name(n), valor(v){};
//~dados();
string GetName(){return name;}
int GetValor(){return valor;}
void SetValor(int x){valor = x;}
}
and this class, which basically reads a file and put the data into a vector:
class FileReader{
vector<Dados> dados;
public:
bool ReadFile(string file) {
dados.empty();
string fnome, ftemp;
int fvalor;
ifstream fich(file);
string linha;
if (fich.is_open())
{
while (fich.peek() != EOF){
getline(fich, linha);
istringstream iss(linha);
//cout << ".";
iss >> fnome;
iss >> ftemp;
iss >> fvalor;
dados.push_back(Dados(fnome,fvalor));
}
fich.close();
return 0;
}
else{
cout << "Ficheiro \""<< file <<"\" nao encontrado!";
return 1;
}
}
int FindOnVector(string fi)
{
int val;
vector<Dados>::const_iterator it;
it = dados.begin();
while (it != dados.end()){
val = it->GetValor();
it++;
}
return val;
}
};
But on class FileReader i need on method for find a name, and return int (valor).
This time he just doing this return value. Not this search a name.
but val = it->GetValor();
Give to me this error on VS 2012:
error C2662: 'Dados::GetValor' : cannot convert 'this' pointer from 'const Dados' to 'Dados &'
someon can me help?
Bests
Make the GetValor method const:
`int GetValor() const {return valor;}`
Declare the getter like this and it will work:
int GetValor() const {return valor;}
The const keyword indicates that calling GetValor does not modify the object.
Not related to your question, but this is wrong:
while (fich.peek() != EOF)
{
// ...
}
You should just have
while (std::getline(fich, linha))
{
// ...
}
To your original question, you need a getter for name that has a const modifier:
string GetName() const
{
return name;
}
The same goes for all your getters if you wish to use them in const functions/iterators.
First of all declare these functions as const
string GetName()const {return name;}
int GetValor() const {return valor;}
Secondly this statement in function ReadFile
dados.empty();
has no any sense. It simply returns true if the vector is empty. I think you meant
dados.clear();
As for searching an element of the vector then it is better to use standard algorithm std::find()or std::find_ifif you will use a lambda expression or a standard predicate . If you will use std::find you need to define operator == for class Dados.
As for your own function that you should decide what it will return in case when nothing was found. Suppose you will return 0. So the function could look the following way
int FindOnVector( const string &fi ) const
{
int val = 0;
for ( const Dados &d : dados )
{
if ( d.GetName() == fi )
{
val = d.GetValor();
break;
}
}
return val;
}