A problem has come up in my application where my PrintAll function will not work correctly and only ultimately crash my application. My app is supposed to read strings from a file and insert them into an array. The problem is it is reading incorrectly and will ultimately crash my app. Here is where I think the problem lies:
int main()
{
LoadMovies();
MovieList *movies = LoadMovies();
//movies->MovieList::PrintAll();
// // test methods for the Movie and MovieList classes
//PrintAllMoviesMadeInYear(movies, 1984);
//PrintAllMoviesWithStartLetter(movies, 'B');
//PrintAllTopNMovies(movies, 5);
//delete movies;
return 0;
}
MovieList* LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
MovieList ml = MovieList(movies.size());
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
ml.Add(movie);
}
ml.PrintAll();
}
Complete Example:
/*
* File: MovieStatsProgram.cpp
* Author:
* Date:
* ===============================================================
* This is a console app to test the Movie and MovieList classes.
*
* TODO:
*
* You need to finish the implementation of the loadMovies method
* to create and initialize the MovieList object.
*
* You also need to create three static methods:
*
* PrintAllMoviesMadeInYear - it will print all the movies made in a
* given year once sort in alphabetical order and once sorted by the number
* of votes with the movie with the most number of votes printed first.
*
* PrintAllMoviesWithStartLetter - it will print all the movies started with
* a given letter sorted in alphabetical order
*
* PrintAllTopNMovies - it will display the top N movies based on the number of
* votes
*/
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
class Movie {
public:
Movie();
Movie(string n, int y, int v, double r);
string get_name();
void set_name(string n);
int get_year();
void set_year(int y);
int get_votes();
void set_votes(int v);
double get_rating();
void set_rating(double r);
string PrintMovie();
private:
string name;
int year_made;
int votes;
double rating;
};
Movie::Movie() {
name = "null";
year_made = 0;
votes = 0;
rating = 0.0;
}
Movie::Movie(string n, int y, int v, double r) {
name = n;
year_made = y;
votes = v;
rating = r;
}
string Movie::get_name() {
return name;
}
void Movie::set_name(string n) {
name = n;
}
int Movie::get_year() {
return year_made;
}
void Movie::set_year(int y) {
year_made = y;
}
int Movie::get_votes() {
return votes;
}
void Movie::set_votes(int v) {
votes = v;
}
double Movie::get_rating() {
return rating;
}
void Movie::set_rating(double r) {
rating = r;
}
string Movie::PrintMovie() {
cout << fixed << setprecision(1) << rating << "\t\t" << votes << "\t\t" << "(" <<
year_made << ")" << "\t" << name << endl;
}
class MovieList {
public:
MovieList(int size);
~MovieList();
int Length();
bool IsFull();
void Add(Movie const& m);
string PrintAll();
private:
Movie* movies;
int last_movie_index;
int movies_size;
int movie_count = 0;
};
MovieList::MovieList(int size) {
movies_size = size;
movies = new Movie[movies_size];
last_movie_index = -1;
}
MovieList::~MovieList() {
delete [] movies;
}
int MovieList::Length() {
return last_movie_index;
}
bool MovieList::IsFull() {
return last_movie_index == movies_size;
}
void MovieList::Add(Movie const& m)
{
if (IsFull()) {
cout << "Cannot add movie, list is full" << endl;
return;
}
++last_movie_index;
movies[last_movie_index] = m;
}
string MovieList::PrintAll() {
for (int i = 0; i < last_movie_index; i++) {
movies[last_movie_index].Movie::PrintMovie();
//cout << movies[last_movie_index] << endl;
}
}
void ReadMovieFile(vector<string> &movies);
MovieList* LoadMovies();
enum MovieSortOrder
{
BY_YEAR = 0,
BY_NAME = 1,
BY_VOTES = 2
};
int main()
{
LoadMovies();
MovieList *movies = LoadMovies();
//movies->MovieList::PrintAll();
// // test methods for the Movie and MovieList classes
//PrintAllMoviesMadeInYear(movies, 1984);
//PrintAllMoviesWithStartLetter(movies, 'B');
//PrintAllTopNMovies(movies, 5);
//delete movies;
return 0;
}
MovieList* LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
MovieList ml = MovieList(movies.size());
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
ml.Add(movie);
}
ml.PrintAll();
}
void ReadMovieFile(vector<string> &movies)
{
ifstream instream;
instream.open("imdbtop250.txt");
if (instream.fail())
{
cout << "Error opening imdbtop250.txt" << endl;
exit(1);
}
while (!instream.eof())
{
string movie;
getline(instream, movie);
movies.push_back(movie);
}
instream.close();
}
When I use MovieList::PrintAll in the main function, my function just crashes, and when I put it in the LoadMovies function, it will read and add data incorrectly before crashing. The size of the list is 251 and the application will just read the same data 251 times.
You have a two part problem:
1: As Brad S stated, your function returns nothing. This is a no-no.
MovieList* LoadMovies()
{
MovieList ml = MovieList(movies.size());
// Your function returns a pointer to a MovieList, so...
return &ml;
}
So, problem #2 is that you're going to return a pointer to something you created on the stack in your function. When you try to access it outside of your function, you'll run into undefined behavior.
Option 1:
MovieList* ml = new MovieList( movies.size() );
return ml;
You now need to delete ml when you're done w/ it.
Option 2:
Change your function to return a non-pointer... then you don't have the hassle of managing the memory.
EDIT: Try this
int main()
{
// Don't need this
// LoadMovies();
MovieList *movies = LoadMovies();
// Uncommented this
delete movies;
return 0;
}
MovieList* LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
// CHANGE
MovieList* ml = new MovieList(movies.size());
// CHANGE
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
ml.Add(movie);
}
ml.PrintAll();
// CHANGE
return ml;
}
Your MovieList class has a fundamental problem. This comes to light on this line:
MovieList ml = MovieList(movies.size());
Your MovieList class has a member that is a pointer to dynamically allocated memory. Once you have this, you have to manage copying and assignment by creating a user-defined copy constructor and assignment operator.
The easiest fix for this is to use std::vector<Movie> instead of Movie * as a member variable of MovieList. Then copy-assignment comes for free and you don't need to implement further functions.
However, if you can't use std::vector for some reason, the following functions can be added:
class MovieList {
public:
//...
MovieList(const MovieList& m);
MovieList& operator=(MovieList m);
//...
};
#include <algorithm>
//...
// copy constructor
MovieList::MovieList(const MoveList& m) {
movies_size = m.size;
movie_count = m.movie.count;
last_movie_index = m.last_movie_index;
movies = new Movie[movies_size];
for (int i = 0; i < movies_size; ++i)
movies[i] = m.movies[i];
}
//...
// assignment operator
MovieList& MovieList::operator=(MoveList m) {
std::swap(m.movie_size, movie_size);
std::swap(m.last_movie_index, last_movie_index);
std::swap(m.movies, movies);
std::swap(m.movie_count, moviE_count);
return *this;
}
The easiest way to describe this to you is not to describe what these do. The best thing for you is to use your debugger and put a breakpoint in any of these functions and step through the code. When you hit the line I mentioned above, you will more than likely see that the copy constructor function is called -- then you can see it in action as to what it is doing.
The assignment operator is the function that's called when you assign an existing MovieList to another MovieList. It's implemented via the copy/swap idiom. This relies on a working copy constructor (provided above), and a destructor (which you already provided in your code). It works by creating a temporary MovieList, and swapping out the internals of the current MovieList with the temporary MovieList. There are many threads on SO as to how this works.
As to the reason why you need these functions above is that without the above functions, the line:
MovieList ml = MovieList(movies.size());
will create two MovieList objects, one temporary and one non-temporary, however the movies pointer for both will be pointing to the same memory. When the temporary is destroyed, the destructor is called, thus deleting the memory pointed to by movies. Now you have m1 pointing to memory that has gone up in smoke. Bad news when you try to use m1.
The user-defined copy and assignment functions above properly copy the object so that you get two distinct memory allocations for movies, so that when the destructor is called, the memory deleted will be unique to that object.
Again, all of this would be alleviated if you used std::vector and forego having to write copy ctor/assignment operators.
Related
I'm getting the error after I delete a pointer from the vector and try to delete a second one. I'm still new to pointers
I created a base class of shapes and have multiple shapes derived classes not shown here and I have to store them in a vector of pointers.
I ask the user to add shapes of their choice measures and calculate the volumes
then I also ask what shapes they want to remove.
#include <string>
#include <iostream>
#include <vector>
#include <iomanip>
#define _USE_MATH_DEFINES
#include <cmath>
using namespace std;
class Luggage {
private:
static double totalVolume;
protected:
string type;
static int count;
static int serialGen;
int serialNum;
public:
Luggage() {
type = "Luggage";
count++;
serialNum = serialGen++;
cout<<"Generating Luggage"<<getSN()<<endl;
}
// 'static' can only be specified in the class header file not source
void static updateVolume(double inVolume) {
totalVolume += inVolume;
}
virtual
~Luggage() {
cout<<"Luggage Destructor"<<getSN()<<endl;
count--;
}
static int getCount() {
return count;
}
string getType() {
return type;
}
string getSN() {
return "(SN: " + to_string(serialNum) + ")";
}
virtual double getVolume()=0;
static double getLuggageVolume() {
return totalVolume;
};
friend ostream & operator<<(ostream & out, Luggage * lptr) {
out<<setw(10)<<left<<lptr->getType()<<": "
<<setw(6)<<right<<setprecision(1)
<<fixed<<lptr->getVolume()<<" ~ "<<lptr->getSN();
return out;
}
};
class Box : public Luggage {
private:
double length, width, height;
static int count;
static double totalVolume;
public:
Box(double l, double w, double h){
count++;
type = "Box";
length = l;
width = w;
height = h;
cout<<"Generating a Box with a Volume: "<<getVolume()<<getSN()<<endl;
updateVolume(getVolume());
}
~Box() {
count--;
updateVolume(getVolume() * -1);
cout<<"Destroying a Box with Volume: "<<getVolume()<<getSN()<<endl;
}
double getVolume() {
return length*width*height;
}
static int getCount() {
return count;
}
static double getTotalVolume() {
return totalVolume;
}
};
int main() {
// Your main program will create a container of luggage and be able to add luggage items
// and remove them as well. This container will be a vector of luggage pointers.
vector<Luggage*> container;
int input; // Main Menu User input
bool io = true;
while(io){
// Main Menu
cout << "\n----Main Menu----\n"
"1) Add Luggage to storage container\n"
"2) Remove Luggage from storage container\n"
"3) Show all luggage\n"
"4) Show total volumes\n"
"5) Exit\n\n"
"Enter: ";
Luggage *lptr;
cin >> input;
if(input == 1){
int shapeChoice;
cout<<"\nWhat Shape do you want? "<<endl
<<"1) Box"<<endl
<<"2) Cube"<<endl
<<"3) Cylinder"<<endl
<<"4) Pyramid"<<endl
<<"5) Sphere"<<endl;
cin>>shapeChoice;
switch (shapeChoice){
case 1: { // Box
double length, width, height;
cout << "\nEnter length of Box: ";
cin >> length;
cout << "Enter width of Box: ";
cin >> width;
cout << "Enter height of Box: ";
cin >> height;
lptr = new Box(length, width, height);
container.push_back(lptr);
break;
}
default:
cout << "Bad choice! Please try again later.\n";
break;
}
}else if(input == 2) {
int count = 0;
for(auto l:container) // container is vector<Luggage*>
cout << ++count << ") "<< l << endl;
cout<<"What element do you want to remove? "<<endl;
int removeChoice;
cin>>removeChoice;
removeChoice-=1;
delete (lptr);
container.erase(container.begin()+removeChoice);
}
}
delete (lptr);
This statement is wrong.
lptr is pointing at the last Box object pushed into the vector. If nothing was pushed yet, this statement causes undefined behavior since lptr is uninitialized before the 1st push. Otherwise, you are destroying the last object pushed, and then you are left with a dangling pointer, which will then fail on the next delete, causing undefined behavior again, unlese you push a new object that updates lptr beforehand.
That statement should be this instead:
delete container[removeChoice];
or safer:
delete container.at(removeChoice);
since you are not validating removeChoice beforehand.
But either way, you really shouldn't new/delete objects manually in modern C++. Use smart pointers instead, in this case std::unique_ptr<Luggage>, and let it deal with destroying objects for you.
I have a class Employee. (Some of my comments are not updated from when I added members tasks and taskList; I apologize for that.)
Employee.h
#include <string>
#include <iostream>
using namespace std;
class Employee {
private:
string employee_name;
string employee_ssn;
string * taskList; //stores an array of tasks for the employee to do
int tasks; //stores the number of tasks an employee needs to do
public:
//constructors
Employee(); //default - nothing
Employee(string, string, string a[], int numOfTasks); //sets both ssn and name
~Employee(); //destructor
//copy constructor:
Employee(const Employee &emp);
Employee & operator =(const Employee& source);
void set_name(string); //sets name in program
void set_ssn(string); //sets ssn in program
string get_ssn(); //returns ssn as string
string get_name(); //returns emp name as string
void display(); //displays both on two separate lines
};
Employee.cpp
#include "Employee.h"
//constructors
//default constructor makes the object empty
Employee::Employee() {
taskList = nullptr;
return;
}
//constructor sets both name and ssn
Employee::Employee(string x, string y, string a[], int numOfTasks) {
employee_name = x;
employee_ssn = y;
tasks = numOfTasks;
taskList = a;
return;
}
//destructor
Employee::~Employee() {
delete [] taskList;
}
//copy constructor
Employee::Employee(const Employee & source) {
//copy simple member variables
employee_name = source.employee_name;
employee_ssn = source.employee_ssn;
tasks = source.tasks;
//allocate new dynamic array for taskList
taskList = new string[source.tasks];
//copy values from one taskList to another
for (int i = 0; i < tasks; i++)
taskList[i] = source.taskList[i];
return;
}
//assignment operator overloading
Employee & Employee::operator =(const Employee& source) {
cout << "Calling the assignment operator overloader.\n";
//check for self assignment
if (this == &source)
return *this; //avoid doing extra work
employee_name = source.employee_name;
employee_ssn = source.employee_ssn;
tasks = source.tasks;
cout << "Substituting 'task list'\n";
//delete former taskList
//if (taskList != nullptr)
delete[] taskList;
cout << "TaskList deleted.\n";
//allocate new one with same capacity
taskList = new string[source.tasks];
//copy values from one to the oher
for (int i = 0; i < tasks; i++)
taskList[i] = source.taskList[i];
cout << "Function complete.\n";
return *this;
}
//postcon: name is set to inputted string
void Employee::set_name(string s) {
employee_name = s;
return;
}
//postcon: ssn is set to inputted string
void Employee::set_ssn(string s) {
employee_ssn = s;
return;
}
//returns ssn as string
string Employee::get_ssn() {
return employee_ssn;
}
//returns employee name as string
string Employee::get_name() {
return employee_name;
}
//precon: name and ssn are both assigned
//postcon: name and ssn printed to the screen w/ labels on two lines
void Employee::display() {
cout << "Name: " << employee_name << endl;
cout << "SSN: " << employee_ssn << endl;
cout << "Tasks:\n";
for (int i = 0; i < tasks; i++)
cout << i + 1 << ". " << taskList[i] << endl;
return;
}
We were instructed to implement a copy constructor and assignment overloading, and we were also specifically instructed to make individual Employee objects dynamically allocated in the main program.
What I seem to be having issue with is the swapping using the assignment overload.
employee_driver.cpp
#include "Employee.h"
#include <iostream>
int main() {
//tasks for each employee to do:
//Tasks to be assigned to Marcy:
string tasks[2] = {"Send emails", "Prepare meeting brief"};
//Taks to be assigned to Michael:
string tasks2[3] = {"Stock up on pens", "Send emails", "Organize union"};
Employee *emp1 = new Employee("Marcy", "678091234", tasks, 2);
Employee *emp2 = new Employee("Michael", "123994567", tasks2, 3);
//display data before swap
emp1->display();
cout << endl;
emp2->display();
cout << endl;
//swap employees
Employee temp(*emp1); //using copy constructor to copy first employee into temporary
*emp1 = *emp2;
*emp2 = temp; //uses overloaded assignment operator to copy values of temp into emp2; Marcy's data is now in Michael's pointer
//display after swap
cout << "\n\nAfter swap:\n\n";
emp1->display();
cout << endl;
emp2->display();
//free heap
delete emp1;
delete emp2;
//delete emp3;
return 0;
}
The issue in question seems to occur here:
*emp1 = *emp2; (towards the bottom of the main program), but I cannot figure out why; any help would be appreciated. I could get around it, but I don't think that's the purpose of the exercise, and I would like to know why this statement is not working correctly.
Thanks.
Within the constructor
Employee::Employee(string x, string y, string a[], int numOfTasks) {
employee_name = x;
employee_ssn = y;
tasks = numOfTasks;
taskList = a;
return;
}
you just store the passed pointer a in the data member taskList,
In main the arrays
string tasks[2] = {"Send emails", "Prepare meeting brief"};
//Taks to be assigned to Michael:
string tasks2[3] = {"Stock up on pens", "Send emails", "Organize union"};
were not allocated dynamically. So you may not in the copy assignment operator call the operator delete [] for such arrays
delete[] taskList;
You need in the constructor to allocate dynamically the array a pointer to which is passed as an argument to the constructor.
Also pay attention to that in the default constructor you need to set the data member tasks to 0.
I'm still a bit stuck on another part on my assignment.
Here is what the prompt is asking:
Now you can modify the LoadMovies function to create a MovieList
object and add each of the Movie objects to it. The function
LoadMovies should return a pointer to the MovieList object. That means
you need to create the MovieList object dynamically and on the heap.
Change the main function and store the returned MovieList pointer in a
variable. To test if everything works as expected, you can use the
PrintAll function of the MovieList object.
Here is my code so far:
class MovieList {
public:
Movie* movies;
int last_movie_index;
int movies_size;
int movie_count = 0;
MovieList(int size) {
movies_size = size;
movies = new Movie[movies_size];
last_movie_index = -1;
}
~MovieList() {
delete [] movies;
}
int Length() {
return movie_count;
}
bool IsFull() {
return movie_count == movies_size;
}
void Add(Movie const& m)
{
if (IsFull())
{
cout << "Cannot add movie, list is full" << endl;
return;
}
++last_movie_index;
movies[last_movie_index] = m;
}
void PrintAll() {
for (int i = 0; i < movie_count; i++) {
movies[last_movie_index].PrintMovie();
}
}
};
void ReadMovieFile(vector<string> &movies);
void LoadMovies();
enum MovieSortOrder
{
BY_YEAR = 0,
BY_NAME = 1,
BY_VOTES = 2
};
int main()
{
LoadMovies();
// TODO:
// You need to implement the Movie and MovieList classes and
// the methods below so that the program will produce
// the output described in the assignment.
//
// Once you have implemented everything, you should be able
// to simply uncomment the code below and run the program.
MovieList *movies = LoadMovies();
// // test methods for the Movie and MovieList classes
//PrintAllMoviesMadeInYear(movies, 1984);
//PrintAllMoviesWithStartLetter(movies, 'B');
//PrintAllTopNMovies(movies, 5);
//delete movies;
return 0;
}
void LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
movie.PrintMovie();
}
}
Now where I'm stuck at is where the professor asks me to modify the LoadMovies in the prompt and turn it into a pointer. I'm drawing blanks. Also for some reason if I try to compile it says:
C:\Users\Andy\Documents\C++ Homework\MovieStatisticsProgram\MovieStatsProgram.cpp:163: error: void value not ignored as it ought to be
MovieList *movies = LoadMovies();
^
The order of your constructor is wrong
MovieList(int size) {
movies = new int[movies_size]; // movies_size hasn't been initialized yet!
movies_size = size;
last_movie_index = -1;
}
It should be
MovieList(int size)
: movies_size{size}, movies{new int[size]}, last_movie_index{0}
{}
Though as #ScottMcP-MVP noted your array should be
Movie* movie;
So your constuctor would be
MovieList(int size)
: movies_size{size}, movies{new Movie[size]}, last_movie_index{0}
{}
Some advice for getting started on the remaining functions
Length function will return how many are current used from last_movie_index.
IsFull will check if last_movie_index == movies_size - 1
Add will need to use last_movie_index to figure out what element in your array to store the movie.
PrintAll will have to iterate from [0] to [movie_count] and print out each element.
Your Add function would look something like
void MovieList::Add(Movie const& m)
{
if (IsFull())
{
std::cout << "Cannot add movie, list is full" << std::endl;
return;
}
movies[last_movie_index] = m; // assigns a copy to your array
++last_movie_index; // Increment the movie index
}
for example lets have a class or struct name Employee with two constructors, a default constructor and a constructor with parameters two strings and an int. why doesn't the following code work?
Employee *employees = (employee*) malloc(sizeof(Employee)*10);
let's say we have an array, size 10, of type string for first name, last name, and one of type int for salary. how to initialize the data members of each object class using the constructor with the parameters?
for (int i = 0; i < 10; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
I've been trying to do this for a few days now but wasn't successful. Also, can anyone tell how to do this using c++'s new and delete operator? and also is there a way this can be done using vectors?
Thank you
header file
class employee{
std::string firstname;
std::string lastname;
int salary;
public:
employee(std::string, std::string , int);
employee();
void setFirst(std::string);
void setLast(std::string);
void setSalary(int);
std::string getFirst();
std::string getLast();
int getSalary();
};
employee::employee(std::string x, std::string y, int z)
{
setFirst(x);
setLast(y);
setSalary(z);
}
void employee::setFirst(std::string x)
{
firstname = x;
}
void employee::setLast(std::string y)
{
lastname = y;
}
void employee::setSalary(int z)
{
salary = z > 0 ? z : 0;
}
std::string employee::getFirst()
{
return firstname;
}
std::string employee::getLast()
{
return lastname;
}
int employee::getSalary()
{
return salary;
}
.cpp file
#define MAX 20
using namespace std;
int main(int argc, char* argv[])
{
int n = 1;
cout << "number of employees: ";
cin >> n;
string firstname[MAX];
string lastname[MAX];
double salary[MAX];
float raise[MAX];
for (int i = 0; i < n; i++)
{
cout << "Employee " << i + 1 <<endl;
cout << "-----------\n";
cout << "First Name: ";
cin >> firstname[i];
cout << "Last Name: ";
cin >> lastname[i];
cout << "Monthly Salary: ";
cin >> salary[i];
salary[i] *= 12;
cout <<"Yearly percentage raise (e.g 10% or 0%): ";
scanf("%f%%", &raise[i]);
salary[i] *= (((raise[i])/100.00) + 1);
puts("\n");
}
employee *employees = (employee*) malloc(sizeof(employee)*10);
for (int i = 0; i < n; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
cout << "TESING USING GET FUNCTIONS" << endl;
cout << "---------------------------\n\n";
for (int i = 0; i < n; i++)
{
cout << "Employee " <<i +1<< endl;
cout <<"-----------\n";
printf("First Name: %s", employees[i].getFirst().c_str());
printf("\nLast Name: %s",employees[i].getLast().c_str());
printf("\nYearly Salary: %d\n\n", employees[i].getSalary());
}
}
If you have an array of Employee instances and Employee is not POD (http://en.wikipedia.org/wiki/POD) you need to allocate memory from the stack using the operator new:
Employee* employees = new Employee[10];
And for having this working:
for (int i = 0; i < 10; i++)
{
employees[i] = Employee(firstname[i], lastname[i], age[i]);
}
you need to implement the operator= in your Employee class:
Employee& operator=(const Employee& src)
{
_firstname = src._firstname;
_lastname = src._lastname;
_age = src._age;
return *this;
}
If this looks like your Employee class:
class Employee
{
std::string first_name;
std::string last_name;
// other members and functions ...
};
Then using malloc() to create 10 of these is a complete and utter failure. The reason why is that yes, you allocated memory using malloc(), but that's all you did. You didn't construct 10 Employee objects. Those std::string members need to be constructed, not merely have memory allocated. So with that call to malloc() you have 10 fake Employees that were "created", and as soon as you attempt to do anything with one of them, then boom goes your program.
Do research on POD and non-POD types. You cannot treat non-POD types (as the class above is non-POD) as you would a POD type. For a non-POD type, the instance must be "officially" constructed, (the constructor must be invoked).
On the other hand, malloc() knows nothing concerning C++ and what is required to create an object correctly via construction. All malloc (and calloc, and realloc) knows is to allocate bytes and return a pointer to the allocated space.
Use a vector instead, it's resizable, it's easier to manage, and as Grady stated in his comment, it's also generally not good practice to use malloc in C++ code (although it's possible). Maybe do something that looks like this:
#include <vector>
...
int size = 10;
std::vector<Employee *> employees;
for(int i = 0; i < size; i++)
{
//as far as pulling in your data, that depends on where it's coming from
Employee *temp = new Employee(...);
employees.push_back(temp);
}
I'm rusty on my C++ but this should work.
Try this way:
#include <iostream>
class Employee
{
std::string m_firstname;
std::string m_lastname;
int m_age;
public:
Employee()
{
m_firstname=m_lastname="";
m_age=0;
}
void setFirstName(std::string firstname)
{
m_firstname=firstname;
}
void setLastName(std::string lastname)
{
m_lastname=lastname;
}
void setAge(int age)
{
m_age=age;
}
void displayEmp()
{
std::cout<<m_firstname;
std::cout<<m_lastname;
std::cout<<m_age;
}
};
int main()
{
std::string fname;
std::string lname;
int age;
Employee *employee = new Employee[10];
Employee *employeeptr=employee;
for(int i=0;i<10;i++)
{
std::cin>>fname;
std::cin>>lname;
std::cin>>age;
employeeptr->setFirstName(fname);
employeeptr->setLastName(lname);
employeeptr->setAge(age);
employeeptr++;
}
employeeptr=employee;
for(int i=0;i<10;i++)
{
employeeptr->displayEmp();
employeeptr++;
}
delete []employee;
return 0;
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
Implementing a class Person with two fields name and age, and a class Car with three fields:
The model
A pointer to the owner (a Person*)
A pointer to the driver (also a Person*)
I am writing a program that prompts the user to specify people and cars. Store them in a vector and a vector. Traverse the vector of Person objects and increment their ages by one year. Traverse the vector of cars and print out the car model, owner s name and age, and driver s name and age.
This is my code so far i need some help about the program i don't know what is the error in this program anyone can anyone tell me please why it not displaying any output.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Person
{
private:
string name;
int age;
public:
Person(string n, int a);
string get_name()const;
int get_age()const;
void increment_age();
void print()const;
};
Person::Person(string n, int a)
{
name = n;
age = a;
}
string Person::get_name() const
{
return name;
}
void Person::increment_age()
{
age += 1;
}
void Person::print() const
{
cout << name << endl;
cout << age << endl;
}
class Car
{
private:
string model;
Person *owner;
Person *driver;
public:
Car(string m);
void set_driver(Person* p);
void set_owner(Person* p);
void print()const;
};
Car::Car(string m)
{
model = m;
}
void Car::set_driver(Person* p)
{
driver = p;
}
void Car::set_owner(Person* p)
{
owner = p;
}
void Car::print() const
{
cout << model << endl;
cout << driver->get_name() << endl;
cout << owner->get_name() << endl;
}
int main()
{
vector<Person*> people;
const int PERSON_SZ = 4;
char * names[] = {"Jim", "Fred", "Harry", "Linda"};
int ages[] = { 23, 35, 52, 59 };
for (int i = 0; i < PERSON_SZ; i++)
{
Person *a = new Person(names[i], ages[i]);
people.push_back(a);
}
vector<Car*> cars;
const int CAR_SZ = 3;
char * models[] = { "Festiva", "Ferrarri", "Prius" };
for (int i = 0; i < CAR_SZ; i++)
{
Car *c = new Car(models[i]);
c->set_driver(people[rand()% (people.size())]);
c->set_owner(people[rand()% (people.size())]);
cars.push_back(c);
}
return 0;
}
To answer your specific question: You are not printing anything.
Add this to your code
for (vector<Car*>::const_iterator iter = cars.begin(); iter != cars.end(); ++iter)
(*iter)->print();
Instead of returning name in get_name, you can print it right there.
Make string to void, & print name in get_name().
So instead of
cout<<driver->get_name();
you'll have to write
driver->getname();
same for owner.
You can entrust the increment or output routines to the std::for_each statement. for_each applies the same action to every element in your container, or to a selected sequence.
It looks like:
void person_routine(Person* currentPerson)
{
currentPerson->increment_age();
}
void cars_routine(Cars* currentCar)
{
currentCar->print();
}
int main()
{
std::vector<Person*> persons;
std::vector<Cars*> cars;
// fill both vectors
for_each(persons.begin(), persons.end(), person_routine);
for_each(cars.begin(), cars.end(), cars_routine);
}
Please check your code carefully and read your compiler output. You may always read about containers and algorithms at the http://cplusplus.com