I think the problem is in main() but this compiles fine but I get no output. I think maybe it's not initalizing correctly because in debug mode it says
"myCharQ {item=0x0018fa00 "ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ̺yâpú" front=-858993460 rear=-858993460 ...}"
How would you rewrite this so that it is proper? I'm just starting out with classes so any help would be useful.
The following is a Array based Queue class
#include <iostream>
#include <cstdlib>
using namespace std;
const int MaxQueueSize = 10; // Queue Struct can hold up to 10 char.
typedef char ItemType; // the queue's data type is char
class CPPQueue
{
public:
CPPQueue();
ItemType item[MaxQueueSize];
void initQueue(CPPQueue q);
bool IsEmpty(CPPQueue q);
bool IsFull(CPPQueue q);
void Enqueue(CPPQueue q, ItemType newItem);
void PrintQ(const CPPQueue q);
void PrintQueueInfo(CPPQueue myQ);
ItemType Dequeue(CPPQueue q);
private:
int front, rear;
int count;
};
CPPQueue::CPPQueue()
{
int front, rear, count = 0;
}
void CPPQueue::initQueue(CPPQueue q)
{
q.front = q.rear = q.count = 0;
}
bool CPPQueue::IsEmpty(CPPQueue q)
{
return (q.count == 0);
}
bool CPPQueue::IsFull(CPPQueue q)
{
return (q.count == MaxQueueSize);
}
void CPPQueue::Enqueue(CPPQueue q, ItemType newItem)
{
if(q.count == MaxQueueSize)
{
cerr << "Error! Queue is full, cannot enqueue item.\n" << endl;
exit(1);
}
q.item[q.rear] = newItem;
q.rear++;
if (q.rear == MaxQueueSize)
{
q.rear = 0; // adjustment for circular queue
}
q.count++;
}
ItemType CPPQueue::Dequeue(CPPQueue q)
{
ItemType theItem;
if(q.count == 0)
{
cerr << "Error! Queue is empty, cannot dequeue item.\n" << endl;
exit(1);
}
theItem = q.item[ q.front ];
q.front++;
if (q.front == MaxQueueSize)
{
q.front = 0; // adjustment for circular queue
}
q.count--;
return theItem;
}
// Function PrintQ() prints the contents of the queue without changing
// the queue. Printing starts at the "front" index and stops before we
// get to the "rear" index. A decrementing counter controls the loop.
//
void CPPQueue::PrintQ(const CPPQueue q)
{
int i;
int qindex = q.front;
for(i = q.count; i > 0; i--)
{
cout << q.item[qindex] ;
qindex = (++qindex) % MaxQueueSize; // adjustment for circular queue
if(i > 1)
cout << ", ";
}
}
// Helper function for the main program below.
void CPPQueue::PrintQueueInfo(CPPQueue myQ)
{
cout << "The queue contains: ";
PrintQ(myQ);
cout << endl;
}
int main()
{
CPPQueue myCharQ;// queue holds characters
char ch; // char dequeued
myCharQ.initQueue(myCharQ);
myCharQ.Enqueue(myCharQ, 'a'); myCharQ.PrintQueueInfo(myCharQ);
myCharQ.Enqueue(myCharQ, 'b'); myCharQ.PrintQueueInfo(myCharQ);
myCharQ.Enqueue(myCharQ, 'c'); myCharQ.PrintQueueInfo(myCharQ);
ch = myCharQ.Dequeue(myCharQ); myCharQ.PrintQueueInfo(myCharQ);
ch = myCharQ.Dequeue(myCharQ); myCharQ.PrintQueueInfo(myCharQ);
myCharQ.Enqueue(myCharQ, 'e');
myCharQ.Enqueue(myCharQ, 'f'); myCharQ.PrintQueueInfo(myCharQ);
myCharQ.Enqueue(myCharQ, 'g'); myCharQ.PrintQueueInfo(myCharQ);
cout << endl;
// print the dequeued characters
while(!myCharQ.IsEmpty(myCharQ))
{
ch = myCharQ.Dequeue(myCharQ);
cout << ch << " ";
}
cout << endl << endl;
return 0;
}
You never initialize the member variables front, rear, and count. You shadow them in your constructor by declaring variables with the same names again. Drop the int and just assign them (though this is not why the values aren't printed correctly, more on that in a bit). Actually, don't do that either; use an initializer list:
CPPQueue::CPPQueue()
: front(0), rear(0), count(0)
{ }
Also, why do you have an initQueue function? You already have a constructor, rely on that to initialize your instance(s) (this is not C!).
Next, functions like IsEmpty are non-static member functions, yet they don't operate on the current instance. Don't take a queue as a parameter, just return if the instance is empty, full, whatever. Your code would have to be used like this:
Queue q;
q.IsEmpty(q);
Just strange. All of your member functions operate this way. When you cann a member function an implicit pointer to the current instance is passed as a hidden parameter (this). Therefore, each time the function is called it operates within the context of the instance it was called upon. You don't need to take an instance as a parameter.
Also realize that all of your functions take their arguments by value. You are going to be creating copies of these queues like crazy. If you modify the argument it will not be seen by the caller. For example:
void CPPQueue::initQueue(CPPQueue q)
{
q.front = q.rear = q.count = 0;
}
That is essentially useless (aside from that fact that an initialize function is unnecessary). The changes to q.front, q.rear, and q.count will not be visible outside of that function as you are operating on a copy.
So even though your constructor is broken due to variable shadowing, this is why you still don't print what you expect to after calling initQueue. You are modifying a copy.
As for your implementation, it is not robust at all. You expose the underlying array to clients of your class. This is a bad idea. The items in a queue should not be directly accessible. What if I decide to muck with the array directly? Now all of your state variables are wrong. front, rear, and count are all potentially invalid as I have modified the state of the queue without going through any of your functions.
It's not even necessary; all I should be able to do is queue and dequeue items. That's it. That's what a queue does. It is not an array, if I want an array I will use one.
So, in summary, kudos on beginning to learn a relatively complex language. Keep at it and don't get discouraged, we all have to learn this stuff at some point.
EDIT: I have to run, but here is a quick rewrite of some of your class. I have removed your typedef for the item type. Why? It is unnecessary. You are not going to change it to another type per some platform or other environmental change, so the typedef only hurts the usability of your class. typedefs are good for things that may change (i.e., int32_t) for some environmental reason, but if they aren't helping you or clients of your code they are just one more thing to get in the way.
class CPPQueue
{
public:
CPPQueue();
bool IsEmpty() const;
bool IsFull() const;
void Enqueue(char newItem);
char Dequeue();
void PrintQ() const;
void PrintQueueInfo() const;
private:
char item[MaxQueueSize];
int front
int rear;
int count;
};
CPPQueue::CPPQueue()
: front(0), rear(0), count(0) { }
bool CPPQueue::IsEmpty() const
{
// you don't actually need the this pointer
// here, but I included it to make it clear
// that you are accessing the count variable
// for the current instance of a CPPQueue
return this->count == 0;
}
I hope this helps you rewrite the rest of your class, gotta go now. I added const in teh declaration of functions that should not mutate the internal state of a CPPQueue. Do a search for "const correctness" to get a better idea of why you would do such a thing. Good luck!
In your constructor:
int front, rear, count = 0;
is wrong. These are local variables that shadow your member variables.
You should use member initializers (with colon after your constructor name) instead.
Also note that you are passing by value all over the place - you probably want to pass by reference instead - look at each function parameter and ask yourself, "do I want a new copy of my parameter or do I want to refer to the same parameter (same memory location) that I passed in?"
CPPQueue::CPPQueue() :
front(0), rear(0), count(0)
{
}
Note: #OP this is elementary-level C++ - you need to read up and get your basics down or you will run into many, many much more difficult to fix problems further down the line.
Related
I'm creating a program that will simulate a race between various runners, using behavior classes to implement different types of runner movements.
To do this, an abstract MoveBehaviour class will be implemented, along with several other concrete sub-classes (etc. WalkBehaviour, SleepBehaviour, SlideBehaviour).
The abstract MoveBehaviour class will require a pure virtual move() function, and the appropriate behaviour will be implemented in the concrete sub-classes. This move() function computes a new position newPos for the runner, given its current position oldPos, and the move() function will return a short, text description of the move in the log parameter (Etc. "walk forward 1 step") , which will be printed to the screen in a later step. I feel as if I'm not returning my log values in these functions correctly, and this relates to another issue.
In the update() function in Runner.cc, I'm supposed to randomly select the runner’s next move behaviour. This involves a new walking behaviour 40% of the time, a sleeping behaviour 40% of the time, and a slide behaviour 20% of the time. I'm supposed to use the new behaviour object to compute a new position that will be stored in the newPos parameter, and then I am to document the move in the runner’s current log data member. Etc if the runner is named Timmy, and the new move behaviour is walking, the current log data member will store the string “Timmy walked one step.”
Going back to my log, I wasn't sure how I would access the string that I declared in each of the move functions for every behaviour class. I noticed there is a getLog() function in Runner.cc, but I feel like it doesn't make sense to use that. This makes me thing I wasn't supposed to declare the "walked one step" strings and such in the move classes but rather in the update classes instead.
Additionally, I don't understand how to get the new behaviour object to compute a new position that will be stored in the newPos parameter and would appreciate some help with that as well.
For getting the log values, I'm just printing the runner's name below and my attempt was going to append whatever was in the log value to this sentence, but I wasn't sure how to access the log values.
I can include the SleepBehaviour and SlideBehaviour classes if needed, but they are practically identical to WalkBehaviour and I figured only one example was needed.
Runner.cc
void Runner::update(Position& newPos){
int r;
r = random(100) + 1;
if(r <= 40){
WalkBehaviour* walk = new WalkBehaviour;
}else if (r <= 40){
SleepBehaviour sleep = new SleepBehaviour;
}else{
SlideBehaviour* slide = new SlideBehaviour;
}
cout << name << endl;
}
Position.cc
#include <iostream>
using namespace std;
#include <string>
#include "Position.h"
Position::Position(int i1, int i2) : row(i1), column(i2){
}
Position::getRow(){ return row; }
Position::getColumn(){ return column; }
void Position::setRow(int r){ row = r; }
void Position::setColumn(int c){ column = c; }
MoveBehaviour.h
#ifndef MOVEBEHAVIOUR_H
#define MOVEBEHAVIOUR_H
#include <iostream>
#include "Position.h"
using namespace std;
class MoveBehaviour
{
public:
virtual void move(Position&, Position&, string&) = 0;
virtual ~MoveBehaviour() = default;
};
class WalkBehaviour : public MoveBehaviour{
public:
virtual void move(Position&, Position&, string&);
virtual ~WalkBehaviour();
};
class SleepBehaviour : public MoveBehaviour{
public:
virtual void move(Position&, Position&, string&);
virtual ~SleepBehaviour();
};
class SlideBehaviour : public MoveBehaviour{
public:
virtual void move(Position&, Position&, string&);
virtual ~SlideBehaviour();
};
WalkBehaviour.cc
#include <iostream>
using namespace std;
#include <string>
#include "MoveBehaviour.h"
void WalkBehaviour::move(Position& oldPos, Position& newPos, string& log) {
newPos.setColumn(oldPos.getColumn() + 1);
newPos.setRow(oldPos.getRow());
log = (" walked one step \n");
}
WalkBehaviour::~WalkBehaviour(){}
First, you need to actually use polymorphism by declaring a pointer to a base MoveBehaviour object that you let point to a derived instance.
Additionally, you need to make sure that you don't leak memory, so I chose std::unique_ptr which is automatically freed upon function exit.
Next, you can simply pass an empty std::string for the function to assign the log to, and use a std::stringstream to construct a line with the name with the move description. The output of this stringstream is then added to the log member in one go.
void Runner::update(Position& newPos) {
int r;
r = random(100) + 1;
std::unique_ptr<MoveBehaviour> movement;
if(r <= 40) {
movement = make_unique<WalkBehaviour>();
} else if (r <= 80) {
movement = make_unique<SleepBehaviour>();
} else {
movement = make_unique<SlideBehaviour>();
}
std::string moveLog;
movement->move(currPos, newPos, moveLog);
currPos = newPos;
std::stringstream ss;
ss << name << " " << moveLog << std::endl;
log += ss.str();
}
Here:
if(r <= 40){
WalkBehaviour* walk = new WalkBehaviour;
}else if (r <= 40){
SleepBehaviour sleep = new SleepBehaviour;
}else{
SlideBehaviour* slide = new SlideBehaviour;
}
you are creating new behaviors and immediately leaking them. You should have assign them ti Runner's MoveBehaviour* behaviour;, deleting its old behavior first:
delete behaviour;
if(r <= 40){
behaviour = new WalkBehaviour;
}else if (r <= 40){
behaviour = new SleepBehaviour;
}else{
behaviour = new SlideBehaviour;
}
Your WalkBehaviour::move() uses log correctly (except that you don't need to enclose text literal into ()
I am trying to write an algorithm to check if a graph is connected, (building a board game in which the map is contained as a graph where Regions are Vertices and Borders are edges).
Each region contains a vector of regions that are its neighbors (vector neighbors).
I build the map and check if its connected in the main() function here:
int main()
{
Map map;
Region r1("R1");
Region r2("R2");
Region r3("R3");
r1.addNeighbor(r2);
r2.addNeighbor(r1);
r2.addNeighbor(r3);
r3.addNeighbor(r2);
map.addRegion(r1);
map.addRegion(r2);
map.addRegion(r3);
map.traversal(r1);
map.isConnected();
return 0;
}
And here is my traversal() and isConnected() method implementation:
void Map::traversal(Region currentNode)
{
visited.push_back(currentNode.getRegionName());
Region* current = ¤tNode;
cout << (*current).getRegionName() << " loc: " << current << endl;
for (auto const & neighbor : (currentNode).getNeighbors())
{
if (std::find(visited.begin(), visited.end(), neighbor.getRegionName()) != visited.end()) {
}
else {
cout << (neighbor).getRegionName() << " neighbors: " << (neighbor).getNeighbors().size() << " location: " << &(neighbor) << endl;
traversal(neighbor);
}
}
}
bool Map::isConnected()
{
cout << visited.size() << endl;
cout << regions.size() << endl;
vector<string> regionList;
for (int i = 0; i < regions.size(); i++)
{
regionList.push_back(regions[i].getRegionName());
}
if (visited.size() == regionList.size())
{
return true;
}
else
{
return false;
}
}
The issue I have here is that for some reason, when I get the neighbors of nodes other than the starting node during the recursion of the traversal function, the function for some reason sometimes no longer remembers the neighbors of the current node being traversed (the output of the (neighbor).getNeighbors().size() will sometimes be equal to 0). Also, the address of the currentNode is not always the same as the address of the original object being referenced, leading me to believe that it is copying the object rather than directly pointing to its memory location.
Any help would be appreciated. I am still very new to C++ and the concept of pointers.
Here's the code for my Region class by request:
Region.h
#pragma once
#include <string>
#include <vector>
using namespace std;
class Region
{
private:
string owner;
string regionName;
int numTokens;
public:
vector<Region> neighbors;
void setOwner(string playerName);
void setRegionName(string name);
void setNumTokens(int num);
void addNeighbor(Region r);
vector<Region> getNeighbors() const;
string getOwner() const;
string getRegionName() const;
int getNumTokens() const;
Region();
Region(string regionName);
~Region();
};
Region.cpp
#include "stdafx.h"
#include "Region.h"
Region::Region()
{
}
Region::Region(string name)
{
regionName = name;
owner = "none";
numTokens = 0;
}
Region::~Region()
{
}
void Region::setOwner(string playerName)
{
playerName = owner;
}
string Region::getRegionName() const
{
return regionName;
}
int Region::getNumTokens() const
{
return numTokens;
}
void Region::setRegionName(string name)
{
regionName = name;
}
void Region::setNumTokens(int num)
{
numTokens = num;
}
void Region::addNeighbor(Region r)
{
neighbors.push_back(r);
}
vector<Region> Region::getNeighbors() const
{
return neighbors;
}
string Region::getOwner() const
{
return owner;
}
In
void Map::traversal(Region currentNode)
currentNode is passed by value. This means currentNode is independent of and (anywhere it matters) a copy of the Region provided as a parameter when invoking traversal. This is the different addresses you are noting with
cout << (*current).getRegionName() << " loc: " << current << endl;
Fix with
void Map::traversal(Region & currentNode)
although
void Map::traversal(const Region & currentNode)
is preferred if you do not intend on changing currentNode inside the function (or as a result of the function). It prevents mistakes, and since you have promised not to change the provided Region, the compiler can take advantage of some tricks and optimizations.
The next boobytrap is
vector<Region> neighbors;
stores copies of whatever is placed in them, not the original. So
r1.addNeighbor(r2);
calls
void Region::addNeighbor(Region r)
which is also pass by value (r is a copy of r2) and
neighbors.push_back(r);
places a copy of r into the vector. End result is r1 does not really know r2, it knows a copy. Modifying r2 after the copy does not effect the copy. You are trapped. You must store pointers.
Region needs to look something more like
class Region
{
private:
string owner;
string regionName;
int numTokens;
public:
vector<Region *> neighbors; // change here
void setOwner(string playerName);
void setRegionName(string name);
void setNumTokens(int num);
void addNeighbor(Region * r); // change here
vector<Region *> getNeighbors() const; // change here
string getOwner() const;
string getRegionName() const;
int getNumTokens() const;
Region();
Region(string regionName);
// ~Region(); not required.
};
Unrelated: Region contains no resources that are not self managed and as a result can take advantage of The Rule of Zero. You can safely remove its destructor. Yes. I know it contains a vector of raw pointers. More on this below.
This can lead you into a memory management nightmare, so you have to make sure you have ownership of those Regions everyone is pointing at nailed down.
Ownership is basically "Who's responsible for the clean-up? Who makes sure what's being pointed at is freed when its no longer required?"
In the case of your example,
Region r1("R1");
Is an Automatic variable. It manages it's own lifetime. It is released when it goes out of scope. You can
r1.addNeighbor(&r2); //pass raw pointer to r2
and r2 will be destroyed on schedule right before r1, which if you think about it is kinda dangerous. r1 still holds a pointer to r2, but r1 is also going out off scope, so you'd need to do something stupid in the destructor or go multi threaded. Region doesn't need a destructor, so you're safe, and if you are multi threaded a whole new set of assumptions are required, like why are you going out of scope in main while you still have threads running?
But what about less trivial cases where you're adding and removing Regions and reshaping the graph dynamically?
This gets ugly fast.
Often people will elect to go with a smart pointer in neighbors to manage the
memory for them. Doesn't work well in your case. Doesn't work well for them in a lot of cases, either.
vector<unique_ptr<Region>> (one-and-only-one pointer) doesn't make any sense because there can be many Regions all pointing at the same Region. So much for uniqueness.
shared_ptr also doesn't make sense because r1 points to r2 and r2 points back to r1. Direct action will have to be taken to eliminate the cycle and this mostly defeats the point of a smart pointer. What if you forget or get derailed by an exception?
There are games one can play with weak_ptr, but in a bidirectional graph who is the shared and who is the weak?
Opinion Warning: I favour Regions using raw pointers and a master list of Regions (vector<unique_ptr<Region>> again, but this time it works) as a member of a Graph class that manages access, insertion, removal, and all the other manipulations the same way you would with a linked list managing the linked nodes.
There may be sharper solutions out there that I'm not seeing.
Edit: Here's one based on M.M.'s comment
class Region
{
private:
string owner;
string regionName;
int numTokens;
public:
vector<string> neighbors; // change here. If you have large numbers of neighbours
// consider using a std::set in place of the vector
void setOwner(string playerName);
void setRegionName(string name);
void setNumTokens(int num);
void addNeighbor(const string & name); // change here. Accepting const reference
// reduces unnecessary copying. May want
// to use the same trick for other methods
// receiving a string
const vector<string> & getNeighbors() const; // change here. Returning const
// reference reduces unnecessary copying
string getOwner() const;
string getRegionName() const;
int getNumTokens() const;
Region();
Region(string regionName);
// ~Region(); not required.
};
This assumes regionName is unique and uses it as the key to access the Region from a master list that looks something like map<string, Region> masterlist;. masterlist manages storage for all of your Regions. Remove a Region from it and If the regionName cannot be found in masterlist you don't have to worry about invalid pointers, you just take note and remove it from neighbors.
Remember to be careful with the subscript operator. In masterlist[name] if name cannot be found, a Region will be default constructed for it and stored. Prefer to use the find method if you are looking for a Region that should exist.
If you have a fixed number of regions, consider using a simple array or std::array in place of the map for masterlist and use the index of the Region in the array as the identifier in place of string.
Supplemental reading: What's the difference between passing by reference vs. passing by value?
struct TodoItem
{
std::string todo;
};
const int MAX_STACK_SIZE = 5;
class TodoStackArray
{
public:
TodoStackArray(); //confusion here<---
bool isEmpty();
bool isFull();
void push(std::string todoItem);
void pop();
TodoItem* peek();
/* for grading purposes we need these following methods */
int getStackTop() { return stackTop; }
TodoItem** getStack() { return stack; }
private:
int stackTop;
TodoItem* stack[MAX_STACK_SIZE];
};
Above, is some declarations and a class from a header file for a current assignment. Our duty was to implement a stack program using this header file. However, I am a little confused as to the purpose of the TodoStackArray() in the Header File. Is this supposed to be a base constructor? Am I supposed to use it for anything??
I understand that this is somewhat situation specific but given that stack Arrays are STL I figured you might all be able to provide some insight. Thanks!
In case you want to see what I did with this header file...
TodoStackArray::TodoStackArray() //This, unsurprisingly, produces an error.
{
stackTop = -1;
stack[stackTop];
}
bool TodoStackArray::isEmpty()
{
return (stackTop == -1);
}
TodoItem* TodoStackArray::peek()
{
if(stackTop ==-1)
{
cout<< "Stack empty, cannot peak."<<endl;
}
else
{
return(stack[stackTop]);
}
}
bool TodoStackArray::isFull()
{
return(stackTop == 4);
}
void TodoStackArray::push(std::string todoItem)
{
if(stackTop >= 5)
{
cout<<"Stack full, cannot add new todo item."<<endl;
}
else
{
stack[stackTop++];
stack[stackTop]->todo = todoItem;
}
}
void TodoStackArray::pop()
{
if(stackTop == -1)
{
cout<<"Stack empty, cannot pop an item."<<endl;
}
else
{
stackTop--;
}
}
Also, to be clear, we were not provided driver software. They will be assessing from their own stuff so we have to write our own driver software to test our functions. Hence the lack of any Main implementation.
Yes, TodoStackArray::TodoStackArray() really is your class' default constructor.
What you are supposed to do with it just as with any default constructor:
How are the class members supposed to be initialized if I create a new TodoStackArray?
The answer depends on what your class is supposed to look like in its initial state.
In you situation, "by default" a stack is empty. Setting the stackTop to -1 was not a bad idea and the rest of your implementation is consistent with that (stackTop == -1 clearly means "empty stack").
The odd thing that happens in your constructor is this:
stack[stackTop];
What is, according to you, the purpose of this line? You are reading the value in your array at a negative index, and we all know this kind of things never end well.
Constructors are made to initialize your data. Here you are reading something you didn't initialize at an index that doesn't exist. Doesn't make much sense, does it? :)
Just get rid of this line and you should be able to move on. Here is an equivalent implementation using member initializer list (which are considered nicer):
TodoStackArray::TodoStackArray() : stackTop(-1)
{
// notice: no body required here
}
Have fun!
How can I retrieve an object from the Flight to be compared to the input (flightNumber) in the main? How do I declare the attributes type in the main?
When I compile, a error message is displayed: invalid conversion of 'int' to '*Flight*' at agent1.delete(flightNumber);.
class Flight
{
int FlightNumber
};
class TravelAgent
{
vector <Flight *> flightList;
};
void Agent::delete(Flight *obj)
{
vector<Flight*>::iterator ptr;
for(ptr=flightList.begin();ptr!=flightList.end();ptr++)
{
if((*Ptr)==obj)
{
flightList.erase(ptr);
break;
}
}
if ((ptr) == flightList.end())
{
cout<<"Flight not found"<<endl;
}
}
int main
{
Agent agent1;
int flightNumber;
cout<<"Enter the number of the flight: "<<flush;
in>>flightNumber;
agent1.delete(flightNumber);
}
You can add(if not present) a getter in Flight class
class Flight{
int FlightNumber;
public:
int getflightNumber(){ return flightNumber;}
};
and go as following:-
void Agent::delete(int flightNumber)
{
vector<Flight*>::iterator ptr;
for(ptr=flightList.begin();ptr!=flightList.end();ptr++)
{
if(((*Ptr)->getflightNumber() == flightNumber)
{
flightList.erase(ptr);
break;
}
}
if ((fPtr) == listFlight.end())
{
cout<<"Flight not found"<<endl;
}
}
Since the code here isn't fully functional, it's hard to give you good advice.
First, your error happens because you call (what seems to be) the member function, void Agent::delete(Flight *obj), with a variable of type int instead of type Flight. The compiler is not able to interpret your Flight object as an int, so it throws an error.
Secondly, you want to know how to retrieve attributes from an object. I will advise you to have a look to accessors and mutators.
If you want to retrieve information hold in your Flight object, you should expose member functions allowing that.
// in your header file
class Flight
{
private:
int flight_number;
public:
// retrieve flight number value
int get_flight_number(void) const;
// allow to set the flight number value
void set_flight_number(int new_flight_number);
// some other member functions
}
// in your source file
int Flight::get_flight_number(void) const
{
return this->flight_number;
}
void Flight::set_flight_number(int new_flight_number)
{
// let's do some verification (do whatever you want)
if (new_flight_number > 0)
{
this->flight_number = new_flight_number;
}
}
This way you will be able to set and access your flight_number by writing, for example :
void test_function(Flight *f)
{
if (f->get_flight_number() == 42)
{
// do some stuff
}
}
int main()
{
Flight *my_f = new Flight();
my_f->set_flight_number = 4242;
my_test_function(my_f);
}
Now, you have enough information to get going.
NOTES :
You heavily use pointers. Modern C++ strongly tends to not! Try to use references or move operation. You can consult this pages for info:
cpp-reference - references
cpp-reference - move semantics
It's a bit hardcore for beginner though. The web is full of great article. about it
You original error is in your main method. You need to change it so that instead of passing the flight number to your delete method, you create an instance of your Flight class.
int main() { // you are also missing parenthesis
Agent agent1;
int flightNumber;
cout<<"Enter the number of the flight: "<<flush; // I don't know what flush is but maybe you meant std::endl
cin>>flightNumber;
Flight flight(flightNumber);
agent1.delete(&flight); // delete takes a Flight* not an int
}
This requires that your Flight class have an appropriate constructor.
class Flight
{
public:
Flight(int flightNumber)
: flightNumber_(flightNumber)
{}
private:
int flightNumber_;
};
Then in your delete method you search your vector for the Flight instance that has the same flightNumber_ as the Flight you want to remove from your vector. This will require your Flight class to have some way of returning it's flightNumber_ member variable.
This is definitely NOT the best way to do this and is far from being in accordance with modern C++ standards but it should get you going.
I have a pretty standard class with some public member functions and private variables.
My problem originally stems from not being able to dynamically name object instances of my class so I created an array of pointers of the class type:
static CShape* shapeDB[dbSize];
I have some prompts to get info for the fields to be passed to the constructor (this seems to work):
shapeDB[CShape::openSlot] = new CShape(iParam1,sParam1,sParam2);
openSlot increments properly so if I were to create another CShape object, it would have the next pointer pointing to it. This next bit of code doesn't work and crashes consistently:
cout << shapeDB[2]->getName() << " has a surface area of: " << shapeDB[2]->getSA() << shapeDB[2]->getUnits() << endl;
The array of pointers is declared globally outside of main and the get() functions are public within the class returning strings or integers. I'm not sure what I'm doing wrong but something relating to the pointer set up I'm sure. I'm writing this code to try and learn more about classes/pointers and have gotten seriously stumped as I can't find anyone else trying to do this.
I'm also curious as to what the CShape new instances get named..? if there is any other way to dynamically create object instances and track the names so as to be able to access them for member functions, I'm all ears.
I've tried all sorts of permutations of pointer referencing/de-referencing but most are unable to compile. I can post larger chunks or all of the code if anyone thinks that will help.
class CShape {
int dim[maxFaces];
int faces;
string units;
string type;
string name;
bool initialized;
int slot;
public:
static int openSlot;
CShape();
CShape(int, string, string); // faces, units, name
~CShape();
void initialize(void);
// external assist functions
int getA(void) {
return 0;
}
int getSA(void) {
int tempSA = 0;
// initialize if not
if(initialized == false) {
initialize();
}
// if initialized, calculate SA
if(initialized == true) {
for(int i = 0; i < faces; i++)
{
tempSA += dim[i];
}
return(tempSA);
}
return 0;
}
string getUnits(void) {
return(units);
}
string getName(void) {
return(name);
}
// friend functions
friend int printDetails(string);
};
// constructor with values
CShape::CShape(int f, string u, string n) {
initialized = false;
faces = f;
units = u;
name = n;
slot = openSlot;
openSlot++;
}
My guess is you use the CShape constructor to increment CShape::openSlot?
You're probably changing the value before it's read, thus the pointer is stored in a different location.
Try replacing openSlot with a fixed value to rule out this CShape::option.
-- code was added --
I'm pretty sure this is the problem, the constructor is executed before the asignment, which means the lhs. will be evaluated after CShape::openSlot is incremented.