Calling Main replaces vector object and overwrites data - c++

I am learning c++ and I can't wrap my head around this problem. I have created a class object which hold information of a vehicle. And the class name is vehicle. Here is the class:
class vehicle {
private:
string vehicleNumber;
int vehicleType;
public:
//Default Constructor
vehicle();
//Overload Constructor - #params<vehicleNumber, vehicleType>
vehicle(string vehicleNo, int type){
vehicleNumber = vehicleNo;
vehicleType = type;
}
//Some stuff to test
string getNo(){
return vehicleNumber;
}
int getType(){
return vehicleType;
}
};
And now in my main I have a void method which then takes in user input and puts the object in a vector. So in my main:
//Ref
void storeVehicle(vector<vehicle>&);
void storeVehicle(vector<vehicle>& createNewVehicle){
string number;
int type;
cout << "Enter Vehicle Number: ";
cin >> number;
cout << "Enter the vehicle type: ";
cin >> type;
vehicle newV(number, type);
createNewVehicle.push_back(newV);
cout << endl;
}
//
Now here is the problem I am facing. Inside of my main method, I am creating the object. And this works perfectly find except if I call the main method again, it initializes the object again and I loose my previous data. I am not sure how to tackle this.
Here is the main method:
int main(){
vector<vehicle> newVehicle;
storeVehicle(newVehicle);
return main();
}
So here I am returning main() again so that it reruns. But when it does, i loose my previous vector which held the data. Now how can I keep the data and keep calling the storeVehicle method?
Edit
I also have a switch case which I am using to determine what the user chooses as an option. It may be to display the vehicle information or it maybe to add a new vehicle. In this case too, how can I add the vehicle without loosing previous data. Here is my switch which is inside another method:
void mainMenu(){
int option;
cin >> option;
switch(option){
case 1: {
vector<vehicle> newVehicle;
storeVehicle(newVehicle);
break;
}
default:
cout << "Wrong option";
}
}
So now in my main method, I am simply calling this switch method. Either way, I loose the data yes?
EDIT
I don't understand why people keep downvoting. Aren't we all here to learn? And yet I get a downvote. Sooner or later, stackoverflow decides to block me from asking questions.

Main isn't intended to be used like that, it's just an entry point for your application.
For what you're looking to do, you would be interested in looping. This way a certain section of your code can be ran repeatedly until a condition is met.
int main(){
vector<vehicle> newVehicle;
while(true)
{
storeVehicle(newVehicle);
}
return 0;
}
Take a look at how different loop types work. https://www.tutorialspoint.com/cplusplus/cpp_loop_types.htm
Also, the one in my example is an infinite loop, since the condition is always true.
EDIT The question was changed.
The problem is that each time you call the mainMenu function that the vector is recreated. Create the vector in your Main function and then pass it by ref into the mainMenu function, so that it can then be passed into your storeVehicle function.
int main()
{
vector<vehicle> newVehicle;
while (true)
{
mainMenu(newVehicle);
}
return 0;
}
void mainMenu(vector<vehicle>& createNewVehicle) {
int option;
cin >> option;
switch (option) {
case 1: {
storeVehicle(createNewVehicle);
break;
}
default:
cout << "Wrong option";
}
}
You'd have to add a header for this function to work.
#include <limits>
void storeVehicle(vector<vehicle>& createNewVehicle) {
string number;
int type;
cout << "Enter Vehicle Number: ";
cin >> number;
cout << "Enter the vehicle type: ";
cin >> type;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
vehicle newV(number, type);
createNewVehicle.push_back(newV);
cout << endl;
}

Related

C++ Vector of Objects, are they all named temp?

New to C++ OOP, I recently learned about classes and objects. I created a straightforward class and menu-driven program that adds a temp object to a vector of movies. I have a quick question that I can't quite understand.
Am I just pushing multiple "temp" objects into the vector?
In my head i'm visualizing this as vector my_movies = {temp, temp, temp}; and continously adding 'temp' objects until the user is done. Is this the right way to picture it?
#include <iostream>
#include <vector>
using namespace std;
class Movie
{
private:
string name;
public:
string get_name() { return name; }
void set_name(string n) { name = n; }
};
void menu() {
cout << "1. Add movie" << endl;
cout << "2. Show Movies" << endl;
cout << "3. Quit" << endl;
}
int getChoice(int &choice) {
cout << "Enter you choice: ";
cin >> choice;
return choice;
}
int main() {
vector<Movie> my_movies;
int choice = 0;
string name;
do {
menu();
getChoice(choice);
switch (choice) {
case 1: {
Movie temp;
cout << "Set user name: ";
cin >> name;
temp.set_name(name);
my_movies.push_back(temp);
break;
}
case 2: {
for (auto &mv : my_movies)
cout << mv << endl;
break;
}
}
} while (choice != 3);
return 0;
}
In your case, when you are calling push_back it will copy your "temp" object, which is a local object on the stack. It will be copied into a new object which is stored on the heap, held by the vector object. The vector will store these as an array internally (the default vector with the default allocator etc).
It's also possible to "move" the object (under C++11 and later), if you understand the difference, but doing push_back(std::move(temp)), which generally gives better performance. In your case it would avoid copying the string member "name", and move it instead, avoiding a new allocation for the string inside the Movie in the vector.
See here for more details on push_back
Appends the given element value to the end of the container.
The new element is initialized as a copy of value.
https://en.cppreference.com/w/cpp/container/vector/push_back
If you are just talking about the name of the movie, it will be what ever is entered from cin. Objects don't have names themselves. The local variable name "temp" is just what you see when you write the code, but is just used to tell the compiler which object is being used - the object itself doesn't have a name form the compilers perspective.

Is there a way to declare objects within a conditional statement?

I'm having trouble figuring out how to properly create an object depending on the user's choice.
In the program, I ask the user which they class they want to be--Knight or Wizard. I take input '1' or '2' to represent Knight and Wizard.
I made a switch statement, and within case 1, I declared an object Knight, and the same for Wizard.
I need to use these objects outside of the switch statement, but I can't. I tried to make a 'default' object by making 'Player player;' but because the Player class has a pure virtual function, I can't do that either.
How do I do this effectively?
This is what I have so far:
int main()
{
std::string plyrName;
int input;
bool foo = false;
std::cout << "What is your name?\n";
std::cin >> plyrName;
std::cin.ignore(1000, '\n');
std::cout << "\nWelcome, " << plyrName << ". What class would you like to be?\n";
std::cout << "1. Knight.\n2. Wizard.\n";
std::cin >> input;
while (input != 1 && input != 2)
{
if (foo == true)
std::cout << "Please enter 1 for Knight and 2 for Wizard.\n";
if (!(std::cin >> input))
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "\n";
std::cout << "Only integers are allowed.\n";
}
else
std::cout << "\n";
foo = true;
}
switch (input)
{
case 1:
{
Wizard player;
break;
}
case 2:
{
Knight player;
break;
}
}
std::cout << "\nHere is your player information summary.\n";
std::cout << player.classType();
system("pause");
return 0;
}
I need to access the player object after is has been created, because I want to output to the user which class they selected. Both Knight and Wizard classes have a function to output this.
EDIT: I have a follow up question. In the diagram, Knight & Wizard have a static variable 'special attack name'. How can I access this variable in the main function? The solution of using unique_ptr means that the pointer will point to the base class Player, thus not allowing access to the derived class members such as the static variable 'special attack name'. Do I have a flaw in my design?
In your case, because you want to accomplish polymorphism, you should go for pointers and references. Why? I would highly recommend this beautiful answer. Why doesn't polymorphism work without pointers/references?
So, should you go for a raw pointer, something like Player *?
In almost all scenarios, you should never ever go for raw pointers and especially, when it points to dynamic memory. Simply because any programming error or an exception might lead to delete getting skipped.
Therefore, I would highly recommend you to go for smart pointers introduced in C++11 like unique_ptr and shared_ptr which follow RAII pattern and guarantee deinitialization.
Here is an example of usage of unique_ptr in your case.
#include <memory>
using PlayerPtr = std::unique_ptr<Player>;
using KnightPtr = std::unique_ptr<Knight>;
using WizardPtr = std::unique_ptr<Wizard>;
int main()
{
...
PlayerPtr playerPtr = nullptr;
switch (input) {
case 1: {
playerPtr = KnightPtr(new Knight);
}
break;
case 2: {
playerPtr = WizardPtr(new Wizard);
}
break;
}
// use playerPtr outside.
}
Edit:
As rightly pointed out by HTNW, you must go for std::make_unique instead of using new. But remember, that is a C++14 concept. You must have compiler support for it.
if you create your variable inside the switch case scope it will get deleted as soon as you leave that scope leading you to UB so you declare it as a pointer so it can outlive the conditional statement ie : you declare it as the base class pointer before & you give it to where it points inside conditional statement
#include<memory>
int main()
{
std::string plyrName;
int input;
bool foo = false;
//create your player ptr
std::unique_ptr<Game_Object> player;
std::cout << "What is your name?\n";
std::cin >> plyrName;
std::cin.ignore(1000, '\n');
std::cout << "\nWelcome, " << plyrName << ". What class would you like to be?\n";
std::cout << "1. Knight.\n2. Wizard.\n";
std::cin >> input;
while (input != 1 && input != 2)
{
if (foo == true)
std::cout << "Please enter 1 for Knight and 2 for Wizard.\n";
if (!(std::cin >> input))
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "\n";
std::cout << "Only integers are allowed.\n";
}
else
std::cout << "\n";
foo = true;
}
switch (input)
{
case 1:
{ // initialize it and it would work perfectly as you intend
player = std::make_unique<WIZARD>();
break;
}
case 2:
{ //****
player = std::make_unique<KNIGHT>();
break;
}
}
std::cout << "\nHere is your player information summary.\n";
std::cout << player->classType();
system("pause");
return 0;
}
Someone correct me if I'm wrong, but objects are only valid within the scope they are created so once you are out of that switch statement those objects are not accessible anymore.
You should declare a GAME OBJECT class object outside the switch statement and then create either the wizard or the knight (as both classes inherit GAME OBJECT).

How to relay cin from main into fucntions and struct above main?

ok so i need to figure out how to place the cin user entered in main into the function, and then from the function into the struct; im clueless on what i need to do in the main not just regarding the code but how it connects (memory wise) what is written into the main with the rest of the program. the #include must be ONLY iostream, vector ANDstring!
p.s at the end i need to print out the films stored in the vector of films
using namespace std;
struct Film
{
string Name;
double Length;
string Producer;
string Lead_Role;
string Type;
};
Film create_film()
{
Film f;
cout << "Enter the name of the movie: ";
getline(cin, f.Name);
cout << "Enter movie length: ";
cin >> f.Length;
cin.ignore;
cout << "Enter the producer: : ";
getline(cin, f.Producer);
cout << "Enter the lead role: ";
getline(cin, f.Lead_Role);
cout << "Enter movie type";
getline(cin, f.Type);
return f;
}
int main()
{
//here i need to figure it out
return 0;
}
I think (it's not completely clear) that you're just looking for
int main()
{
Film my_film = create_film();
// do something with my_film
...
return 0;
}
The way I've used create_file() in main is called a function call. It's how you 'connect' one function to another, though 'transfer control' is probably a better way of saying it. When you call a function control transfers from the calling function (main in this case) to the called function (create_film in this case). When the called function returns control goes back to the calling function. And of course when the main function returns the program terminates.

How to display all the elements stored in a vector?

class vehicle{
private:
vector<string>carList;
public:
void info();
void displayCarInfo(vector<string>&carList);
}
void vehicle::info(){
char a;
string choice;
do{
cout<<"Please enter your car Reg number: ";
cin >> carPlate;
carList.push_back(carPlate);
cout << "Do you want to continue add car info(y/n)?";
cin >> choice;
}while(choice == "y");
}
void vehicle::displayCarInfo(vector<string>&carList){
for(int i = 0; i < 100; i++){
cout << carList[i];
}
}
//----------------------------------------------------------------
int main(){
vehicle a;
a.displayCarInfo(carList);
return 0;
}
Questions:
Error show when display all the car list. How to solve it?
And how I can retrieve information for particular element inside carList?
You don't need to pass the vector as an argument to void displayCarInfo();:
class Vehicle{ //<--- define classes starting with uppercase
private:
vector<string>carList;
public:
void info();
void displayCarInfo();
}; //<----- you need a semicolon here
The termination condition should be the vector size.
void vehicle::displayCarInfo(){
for(int i = 0; i < carList.size(); i++){
cout << carList[i];
}
}
The in the main():
int main(){
vehicle a;
a.displayCarInfo();
return 0;
}
If I consider that the and header files were included then too, the program has so many stray compilation errors. Did you not check those ??
Like: choice and carPlate was never declared. Class doesn't end with a ';' etc.
Issues: 1. You create a vehicle 'a' and never put anything in the member variables. I guess the info() function was supposed to do that, then why wasn't it called. I guess you'd need to do that in some loop.
You made the carList vector private and tried to pass the same as an argument from main to the displayCarInfo() func. I hope you realize that such a thing won't be required as being a member function to that same class it can access the carList directly. you simply need to call the public function using an object.
Since Vectors are unbounded (meaning their range can grow and shrink) it's not a good idea to print the content of an vector using a constant loop. That way you always risk a chance of either overrunning the loop or under-running it.
prefer
for vector<string>::iterator it = carList.begin(); it!= carList.end(); it++) std::cout << *it << std::endl;
Although there are smarter ways to do the same using ostream_iterators and std::copy, but that can rest for now.

Stop send value to next function

I have this working code:
/* Include files */
#include <iostream>
#include <string>
#include <limits>
using namespace std;
void fnMainMenu(char s);
/******************************************************************************
* Function: fnUpdateSalary
* Description: Update employee salary
******************************************************************************/
void fnUpdateSalary()
{
int choice = 0;
char data = 'a';
incorrect_input: // goto teleport exit :)
cout<<"\n\t=======================";
cout<<"\n\tWelcome\n";
cout<<"\t=======================\n\n";
cout<<"1. Update employee salary\n";
cout<<"2. Main menu\n";
cout<<"3. Exit system\n";
cout<<"\n >> ";
cin>>choice;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
switch(choice){
case 1 :
//fnUpdateSalary();
break;
case 2 :
fnMainMenu(data);
break;
case 3 :
exit(1);
break;
default :
cout<<"Input not recognized. Please enter the correct input.\n";
}
}
void fnLog()
{
char data = 'b';
fnMainMenu(data); // call Main Menu and I want to pass "hello"
}
/******************************************************************************
* Function: fnMainMenu
* Description: Menu for the customer
******************************************************************************/
void fnMainMenu(char s)
{
cout << s;
if (s == 'a')
{ cout << "a = admin";
}
else
{cout << "\n\nb not admin";
}
//system("cls");
int chooice = 0;
cout<<"\n\t=======================";
cout<<"\n\tWelcome\n";
cout<<"\t=======================\n\n";
cout<<"1. Manage employee\n";
cout<<"2. Search employee\n";
cout<<"3. Employee report\n";
cout<<"4. Reset password\n";
cout<<"5. Exit system\n";
cout<<"\n >> ";
int numbers = 2;
cin>>chooice;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
switch(chooice){
case 1 :
fnUpdateSalary();
break;
case 4 :
// fnChangePassword();
break;
default : exit(1);
}
}
/******************************************************************************
* Function: main
* Description: The main calling function
******************************************************************************/
int main()
{
fnLog();
return 0;
}
fnLog() send b to fnMainMenu(). When I am at fnUpdateSalary() I want to go to fnMainMenu() again. My question is, is there anyway from fnUpdateSalary() or whatever function available to call fnMainMenu() without declaring variable data again? I was hoping I could just use fnMainMenu(); instead of
char data = 'r'; fnMainMenu(data);
I get this error error C2660: 'fnMainMenu' : function does not take 0 arguments if I just called fnMainMenu();
I hope my question make sense. Thanks in advance.
The parameter doesn’t seem to serve a real purpose anyway. Passing b into the main menu function certainly achieves nothing. If you just want to distinguish between admin and non-admin access, change the type and usage of the argument:
void fnMainMenu(bool is_admin) {
if (is_admin)
cout << "Admin\n";
else
cout << "Not admin\n";
}
And call it like this:
fnMainMenu(true);
// Or, alternatively:
fnMainMenu(false);
That’s it. Incidentally, you don’t need (and shouldn’t!) declare a variable to pass as the argument here. Just pass the value directly, like I’ve done above.
Also, why are your function names prefixed by fn? Don’t do this, it’s not good practice. Just use proper names that explain well what the functions do.
If I fully understand what you are doing, you need a combination of two things. Firstly, a static variable in fnMainMenu and secondly a default parameter:
fnMainMenu(char s = '\0')
{
static char c;
if(s != '\0') c = s;
...
...
}
The "static" keyword means that the character will be preserved across function calls. The default parameter means that s will be assigned a null termination character unless you explicitly pass another value.
Since you're writing C++ code and data seems to be relatively long-lived with respect to the application logic, it would perhaps make sense to regroup these functions into a class.
data could be a data member of this class, and fnUpdateSalary, fnLog, fnMainMenu methods.
class Application {
public:
Application ()
: data ('b') // default value
{ }
void fnLog() {
data = 'b';
fnMainMenu ();
}
void fnMainMenu() {
if (data == 'a')
cout << "a = admin";
else
cout << "\n\nb not admin";
// ...
fnUpdateSalary ();
// ...
}
void fnUpdateSalary() {
// ...
fnMainMenu ();
// ...
}
private:
char data;
};
int main () {
Application app;
app.fnLog ();
}