Static class variable initializing to 100 by itself - c++

This is my first question on here, so excuse me if I've formatted everything in a wrong way.
So, to get to the problem - this is s university assignment of mine. The goal is to create a class called Student, which has a few fields, and store the instances in an array of Student objects. One of the tasks is to have a static variable inside the class that keeps track of how many Student instances have been created. To clarify, I have a getData() method that asks the user for the values, and then sets the current object's values to those entered (basically just like a constructor, which makes the constructors obsolete, but they want us to do it that way for some reason). In the getData() function, the static count variable gets raised by 1, as well as in the constructors, and gets decremented in the destructor.
The issue is that for some reason, Student::amount variable sets itself to 100. Every time that i try to access it from the main() function, its 100 plus the amount of students created, so if we have created 2 students, Student::amount will be equal to 102. I've nowhere explicitly set it to that number, which also matches the size of the array, by the way.
I'm still rather new to C++, I've read and watched some material on how OOP works here, but I've barely even scratched the surface.
Sorry again if my question is badly formulated or/and badly formatted, and I hope you can help me with this!
#include <iostream>
#include <string>
using namespace std;
class Date {
...
};
class Student {
// Fields
private:
string name = "";
string PID = "";
int marks[5]{ 0 };
short course = 0;
public:
// Count of all students
static int amount;
// Getters
...
// Setters
...
// Constructors
Student(); // Default one, Student::amount gets raised by 1 there
Student(string name, string PID, int marks[5], short course);
// Destructor
~Student();
// Methods
void getData();
void display(); // Display the information of a student
};
// Array of students
Student students[100];
// Student::Count
int Student::amount; // Initializes with 0 if not explicitly initialized
void Student::getData() {
cin.ignore();
cout << "\nName: "; getline(cin, name);
cout << "PID: "; getline(cin, PID);
cout << "Marks:\n";
for (int i = 0; i < 5; i++)
{
cin >> marks[i];
}
cout << "Course: "; cin >> course;
Student::amount++;
}
Student::Student(string name, string PID, int marks[5], short course) {
this->setName(name);
this->setPID(PID);
this->setMarks(marks);
this->setCourse(course);
Student::amount++;
}

The global declaration Student students[100]; calls the default Student constructor 100 times, before main is reached. According to your comment (you don't supply the constructor implementation), that constructor increases amount by 1.
A solution here is to remove Student::amount and instead use
std::vector<Student> students;
students.size() will give you the number of students in that container. Use push_back to put students into the vector.
A very crude alternative that at least is broadly compliant with the question constraints is to remove the amount increment from the default constructor, and all other places apart from the four argument constructor.

Related

I am getting garbage value while using operator overloading

I have got a question -
Write a c++ program to calculate Gross salary(net salary+DA+TDS) for 4 employees where overload the + operator for getting the total salary obtained by all the 4 employees. Also get the average salary of employees by operator overloading. display all the details of all four employees. Also display who is getting highest salary. Employee salary must be entered by the user at runtime.
#include<iostream>
#include<string>
using namespace std;
class Employee
{
private:
int net_salary, DA, TDA, Gross_salary;
public:
void SetData(int net, int da, int tda, int gross)
{
net_salary=net;
DA=da;
TDA=tda;
Gross_salary=gross;
}
void GetData()
{
cout << "Enter net salary: "<<net_salary;
DA = (15*net_salary)/100; //Declaring the value of DA as 15% and calculating the amount
//on basis of net salary of the employee
TDA = (10*net_salary)/100; //Declaring the value of TDA as 10% and calculating the amount
// of TDA on basis of net salary
Gross_salary = net_salary+DA+TDA;
}
void DisplayData()
{
cout << "Total Gross Salary = "<<Gross_salary;
}
Employee operator +(Employee e)
{
Employee temp;
temp.Gross_salary=Gross_salary+e.Gross_salary;
return temp;
}
};
int main()
{
Employee e1,e2,e3,e4,e5;
e1.GetData();
e2.GetData();
e3.GetData();
e4.GetData();
e5=e1+e2+e3+e4;
e5.DisplayData();
return 0;
}
The trouble comes from the absent initial values for the data members.
// ...
cout << "Enter net salary: " << net_salary;
DA = (15*net_salary)/100;
// ...
Here, in the GetData() member function, that is called after you have created five default initialized objects e1,e2,e3,e4,e5 of Employee type. The net_salary here is of built-in type and is default initialized by the implicitly defined default constructor, hence it has an undefined value. Then you assign this undefined value to the DA and so on in the body of the GetData().
You should not look toward the SetData() as a solution for this, since it should act as a setter method, a method used to modify an already initialized object. You will need to implement constructor(s) for your class, or you can at least supply in-class initializers for the members, like so:
// ...
int net_salary=0, DA=0, TDA=0, Gross_salary=0;
// ...
I can't help but notice that GetData() either has a confusing name or tries to do more than it is intended to do. It does some internal computation, which is ok for a GetSomething function, but it modifies internal data while does some prints.
Also, note the line (in the GetData()):
Enter net salary:
Will be followed by an output, you won't be given a chance to input any data in the GetData(). I assume, you may want to create a constructor that takes input from a user, and then call a function to do all the needed computations.

Using getters and setters with user input in c++

Apologies in advance if this is below the community's paygrade. I just started learning about OOP and English is not my native language.
I just learned about using getters and setters, and the importance of data encapsulation. However, All the examples I've seen online using getters and setters all deal with static values such as the one below:
#include <iostream>
using namespace std;
class Employee {
private:
// Private attribute
int salary;
public:
// Setter
void setSalary(int s) {
salary = s;
}
// Getter
int getSalary() {
return salary;
}
};
int main() {
Employee myObj;
myObj.setSalary(50000);
cout << myObj.getSalary();
return 0;
}
I've managed to allow user input by declaring another set of variables and feeding them as parameters into the setters like below:
int main() {
Employee myObj;
int salary;
cout<<"Enter salary: " << endl;
cin>>salary;
myObj.setSalary(salary);
cout << myObj.getSalary();
return 0;
}
Is this the only way to allow user input? Is there a more elegant way of accomplishing this other than declaring another set of local variables?
Sorry if this is a beginner question. I'm new to the C++ game and am still getting my feet wet.
Is this the only way to allow user input? Is there a more elegant way of accomplishing this other than declaring another set of local variables?
(and from comment)
I was hoping I could do some variation of myObj.setSalary(cin) so cin would feed the value directly into the getter without me having to pass it into temp variables
I would not mix input from stdin with setters, better keep them as seperate methods:
class foo {
int x;
int other_member;
public:
void set_x(int a) { x = a; }
void set_other_member(int a) { other_member = a; }
void read_x(std::istream& in) {
in >> x;
}
};
This lets you write
f.read_x(std::cin);
to read x from stdin.
Note that there are many ways to accomplish the same and what is "elegant" is rather subjective. Typically you would provide an overload for operator>> to read a foo from a stream:
std::istream& operator>>(std::istream& in, foo& f) {
int a,b;
in >> a >> b;
f.set_x(a);
f.set_other_member(b);
}
Either this (using the setters) or you make the operator a friend of foo (to access privates directly) or you use foo::read_x to implement it. Then you can write
foo f;
std::cin >> f;
Note that C++ is not a "pure" OOP language, and idiomatic C++ will happily eschew certain OOP principles in favor of simpler and more effective code where applicable.
It is perfectly acceptable, if you want a datatype to just "hold" data, to use a plain old struct (with public data fields). Don't confuse the benefits of encapsulation (...of non-trivial constructs, so you can change their implementation internally) with any kind of "security". Getters/Setters or not, anyone can change your object's data if he wants to. Incidentially, this makes reading data easier.
cin >> e.salary;
If you don't want "just a struct", it is good style to have a constructor that sets meaningful initial values, so that you don't have "uninitialized" Employee objects flying around (RAII). This means that neither your client nor your destructor has to deal with the possibility that Employee might not actually be one (hold null pointers, or other kinds of uninitialized resources).
Employee e( "Mark Smith", 10000 );
Once you are at that point, Employee should be responsible for anything that happens to / with an Employee object. That implies that it should not be somebody else that's reading user input and writes it to Employee data fields (via setters or not), it should be a message sent to the Employee object that it should update its fields, from input or otherwise, as appropriate.
(Consider the possibility of someone setting a pointer member of yours to nullptr, or worse, some random value. Your destructor would throw a fit trying to free the resource, and then how you'd debug where that invalid pointer came from?)
At which point we arrive at the operator>>(), which can be overloaded for istreams and your class.
class Employee
{
public:
// ...
friend istream & operator>>( istream &, Employee & );
// ...
};
istream & operator>>( istream & in, Employee & e )
{
getline( e.name, in );
in >> e.salary;
return in;
}
int main()
{
Employee e; // For the sake of example, a default constructed employee
cout << "Enter new employee's name (on its own line), and salary:\n";
cin >> e;
}
And once there, you get an idea of what data encapsulation actually means: Employee is an object, not a data container. You should not poke around in it's innards, you should send messages.
Employee e( "Mark Smith", Role::INTERNEE, 10000 );
cout << e; // Output: "Mark Smith, Internee, with an income of 10.000 sicles."
e.promote( Role::TEAM_LEAD, 10000 ); // Exception: "Wrong pay scale for Team Leads."
e.promote( Role::TEAM_LEAD, 30000 );
cout << e; // Output: "Mark Smith, Team Lead, with an income of 30.000 sicles and a free car."
Note how the Employee class sanity-checked the new salary, and knew that a promotion to Team Lead automatically included a free car, and did that without you having to set that yourself. That is what this encapsulation is about...
As for your question "as asked", whether your implementation could do read a salary more elegantly, you could of course...
void setSalary(istream & in) {
in >> salary;
}
...and...
cout << "Enter salary:" << endl;
e.setSalary( cin );
And because that's properly encapsuled, you could add sanity checks, change the type of salary to BigNum, or start support reading in hieratic.
THIS QUESTION IS A GENERAL ANSWER WILL COVER YOU QUESTION
So in OOP, making and using only the copy or the OBJECT is a core concept, the way you are making a single copy OBJECT of a class is a standard one, but have you ever thought about MAKING AN ARRAY OF TYPE "YOUR CLASS's Objects"? because in your case the obj will only hold only one copy of Employee but if you use a data structure e.g "Array" for storing a number of objects then it will be a lot easier let me clarify for you
EXAMPLE
int a, b, c, d, e, f, g ... z;
assigning all of these alphabets a value will be a huge pain but wait you can have a data structure for it.
int arrayOfAlphabets[26];
now you want to assign values? (you can assign it dynamically but this is just an example to show you that you can just control the assigning of a variable with just a counter)
for(int x = 0 ; x < 26; x++){
arryOfAlphabets[x] = someNumber
}
Want to get Values? you can get values dynamically but this is just an example to show you that you can just control the setting & getting of a variable with just a counter)
for(int x = 0; x < 26; x++){
cout << "Value of Alphabet" + x + " is: " + arrayOfAlphabets[x] << endl;
}
now you have seen the example that making a data structure specific data type can remove a lot of pain of yours now keep in mind for the sake of understanding,
YOUR CLASS IS DATATYPE THAT YOU CREATED
class Employee {
private:
// Private attribute
int salary;
public:
// Setter
void setSalary(int s) {
salary = s;
}
// Getter
int getSalary() {
return salary;
}
};
and in main what you can do is
int main(){
Employee emp[5];
int tempSalery;
for( int i=0; i<5; i++ )
{
cin >> tempSalery;
emp[i].setSalery(tempSalery);
}
}
now to print out your result
for( int i=0; i<5; i++ ){
cout << "Employee " + x + "Salery is: " + emp[i].getSalery() << endl;
}

Trying to create a class array in another class

Trying to build a database using classes.
This is just an excerpt of the classes, my main() creates a bunch of students using the class Student. Each student then has an ID and Name that are inputted later. Additionally, each student will have an array of 2 slots which will hold info for their courses they're taking. Those courses are created using the class Course.
What I'm trying to figure out is how can I place the course info (courseID and courseName) into a slot of the student's courses array once I assign them a course (in other words, student A is now in class 1. I want the courseID and courseName of class 1 to be assigned to student A's courses).
I try to use the locations of each course created in the main but that proves difficult trying to output. Is it possible to be in the class Student and have it call a function from class Course? Any help be great. Thanks.
class Course {
protected:
int courseID;
char* courseName;
public:
Course() {
courseID = 0;
courseName = "";
}
void makeID(int id, char* name) {
courseID = id;
courseName = name;
}
int getID() {
return courseID;
}
char* getCourseName() {
return courseName;
}
};
class Student : public Course {
private:
int studentID;
char* studentName;
int classCount;
int courses[2]; //could I change to: Course courses[2]?
char name[30];
int id;
public:
Student() {
studentID = 0;
studentName[30];
classCount = 0;
courses[2];
}
void makeStudent() {
cout << "Input 9 digit student ID: ";
cin >> id;
studentID = id;
cin.ignore();
cout << "Input first and last name of the student: ";
cin.getline(name, 30, '\n');
studentName = name;
return;
}
int getstudentID() {
return studentID;
}
int getclassCount() {
return classCount;
}
char* getstudentName() {
return studentName;
}
void addClass(int course) {
if (classCount == 2) {
cout << "Max amount of courses reached." << endl;
}
else {
courses[classCount] = course;
classCount++;
}
return;
}
int returnClass(int course) { //can't figure out what to do
return courses[course]; //here.
}
};
At very first, you should get a clear image how your data model shall look like.
OK, we have bunch of courses and a bunch of students. Courses and students are totally unrelated (apart from students attending courses) concepts at first, so it won't make any sense one inheriting from the other...
Imagining the scenario does not only cover one single period (school year, semester, trimester, ...), courses might change over time as well as will the students.
So you might have a vector or another data structure storing courses on one hand and students on the other.
Students will attend courses, this can be reflected in two ways:
courses holding lists of all students attending them
students holding lists of all courses they attend
Depending on use case, it might be appropriate to implement both redundantly.
How would you install such a relation ship? Easiest (at a first glance, at least) would be X holding one or more pointers to Y in both scenarios.
class Course
{
std::vector<Student*> participants;
public:
// whatever you need...
};
class Student
{
std::vector<Course*> students;
public:
// whatever you need...
};
As I now use pointers to represent the relation ship, the data structures holding all courses and students must not invalidate these if adding or removing students from! std::vector<X> would do so, so you cannot use it. Alternatives would be std::vector<std::unique_ptr<X>> or std::list<X>. Actually, std::vector<X*> would work as well, but then it would be you who would need to care for deletion, if removing courses or students, so prefer one of the other solutions.
But why did I not use smart pointers for the courses' and students' vectors? We'd be forced to use std::shared_ptr then for, but we won't profit from: If a student leaves our institution, we'd have to eliminate her/him anyway and remove her/him from all courses being attended. So we don't profit from smart pointers in this scenario (can be totally different in other ones). Analogously if a course is cancelled.
So make sure in the destructors the classes that
a course is removed from all students' vectors in its own vector
student is unregistered from all courses in its vector
With these basics, you can get ID, name and other data for a specific course a student attends simply via the pointer in the vector.
If you often seek via a specific information, (e. g. by name), you might have a std::map as well, facilitating the lookup by the specific attribute. You might use such a map for the complete list of courses/students as well, then, though, be aware that pointers are only guaranteed to remain valid in std::map<X, Y>, not in std::unordered_map<X, Y>, so if you intend to use the latter, you'd have to go the way via smart pointer again as with the vector: std::unordered_map<X, std::unique_ptr<Y>>.

trouble making c++ student class [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
For my assignment I have to make a program to read student data from standard input, sort it by last name / first name, and print out the result to standard output. Students consists of a last name, first name, and a grade point average. It says to there are no more than 50 students.
It also says you should not rely on an external library function to do the sort.
Here is the example:
Ware Henry 87.2
Dantes Edmond 91.4
Earhart Amelia 92.6
Here is how it should be sorted:
Dantes Edmond 91.4
Earhart Amelia 92.6
Ware Henry 87.2
Here is the code I have so far that is not working properly:
#include <iostream>
#include <string>
using namespace std;
class student
{
public:
student();
void input();
void output();
void sort();
private:
string Fname;
string Lname;
float gpa;
}
student::student()
{
Fname = "";
Lname = "";
gpa = 0;
}
void student::input()
{
cout << "Enter first name, last name, and gpa"<<endl;
cin >> Fname >> Lname >> gpa;
}
void student::sort()
{
char temp;
int count = 0;
int i = 1;
while (i < word.size()) {
if (word[i - 1] > word[i]) {
temp = word[i];
word[i] = word[i + 1];
word[i + 1] = temp;
i++;
if (i >= word.size())
{
alpha(word);
}
}
else
{
count++;
}
}
return word;
}
void main()
{
student.input();
}
Any advice on where I went wrong and any possible solutions?
your student class has member variables to hold only one student, you need 50 instances of class student.
then you should hold these instances in an array/vector (whatever for container you are allowed to use) I assume you need to use a raw array so something like this will do.
student* students = new student[50];
what you then need is a compare function in your class to be able to sort the array, the compare function knows the internals of your class and you can decide how you want to sort the list e.g. after surname.
the sort function could be inside your class declared as a static function or maybe more logically an external function since student is not a container of student instances.
don't forget to delete the array when done
delete [] students;
in real world problems you would use std containers and e.g. algorithm sort for this kind of work.
Your compiler must have told you that word and alpha used in sort method are undeclared identifiers and count is assigned but never used.
Solution: Never ever steal code from wild wild web without understanding what it does. You may take others' code as inspiration, but blind copy-paste is a big no-no.
To give you a next step: you haven't even stored your students, you just input one, how would you sort just one entry? Think (and code) what you should use to store them and start working from there on how to sort them.
Good luck.
There are several reasons why your code is not working, first reason is that your class definition needs semicolon ';' at the end to close it.
class student
{
public:
student();
void input();
void output();
void sort();
private:
string Fname;
string Lname;
float gpa;
}; //semicolon here
In your sort() method the variable word is used but never declared, coding is not magic, the variable must declared and initialized before it is used like in your code.
while (i < word.size()) { //word must be declared somewhere
Also, in the sort method, you call a function alpha(word), this function does not exist in your program.
The sort method is of type void, which means it will not return anything, yet you are trying to return a string.
Another problem with the sort method is that it is never called from anywhere and will never be run.
There is also a big problem here with the way you are trying to use your class. To use the methods of the class you first have to instantiate an object of that class, you can then access the methods of the class through the object like this:
int main()
{
student theStudent;
theStudent;
theStudent.input();
return 0;
}
Another fundamental problem is that you are only going to get data for one object like this, you need to store several objects in something like an array and then sort the objects in the array:
int main()
{
student students[5];
for (int i = 0; i < 5; i++)
{
student newStudent;
students[i] = newStudent;
newStudent.input();
}
sort(students);
delete[] students;
return 0;
}
Which brings us to the sort method. It would be wise to not do the sorting as a method of the student class, but as a function called from main instead (like in the example above), that way it is easy to sort the array of student objects from main.
These are a few advice to start with, i am not going to do your complete homework for you though, if you use google and some of your precious energy, i believe that you will succeed.

Not understanding what is being asked and how to type them?

I am having trouble understanding some parts of the question for this program and would like to know why and how to type the program. Here are the parts I'm unable to understand:
The third member variable is a pointer to a double, pquiz. This will be used to dynamically allocate an array which will hold a student's quiz grades.
(Did I do this correctly?)
The fourth member variable is a double holding the average value of the quiz grades.
The class should have a one parameter constructor which accepts an int and will dynamically allocate the array of double quiz grades. Or the class can >have a two parameter constructor which accepts both a string and an int.
The int is the number of quiz grades
The constructor uses the new operator to allocate memory for the array of quiz grades.
If there are two parameters, the string is the student's name.
The class needs the usual mutator, accessor functions and a destructor function.
The class has an additional function, average(), which calculates the average of all the quiz grades held in the array pointed to by pquiz. It returns the double average value.
I'm suppose to print a students name, number of tests the student took, and the average. Here is my program so far:
#include <iostream>
#include <string>
using namespace std;
class TestScore{
private:
string name;
int grades;
double *pquiz;
double average;
public:
TestScore();
void setName(string);
void setGrades(int);
void setAverage(double);
string getName();
int getGrades();
double getPquiz();
double getAverage();
};
TestScore::TestScore()
{
name="?";
grades=0;
pquiz=0;
average=0;
}
void TestScore::setName(string name1)
{
name=name1;
getline(cin,name1);
}
void TestScore::setGrades(int grades1)
{
grades=grades1;
}
void TestScore::setAverage(double average1)
{
average=average1;
}
string TestScore::getName()
{
return name;
}
int TestScore::getGrades()
{
return grades;
}
double TestScore::getAverage()
{
return average;
}
int main()
{
TestScore exam;
TestScore *ts=&exam;
string name;
int grade;
double *pquiz;
double average;
double total=0.0;
int count;
cout<<"Enter student name: ";
exam.setName(name);
cout<<"How many quizzes are there? ";
exam.setGrades(grade);
cin>>grade;
pquiz=new double[grade];
for(count=0; count<grade; count++)
{
cout<<"Quiz "<<(count+1)<<": ";
cin>>pquiz[count];
}
for(count=0; count<grade; count++)
{
total+=pquiz[count];
}
average=total/grade;
cout<<exam.getName()<<" has an average of "<<average<<endl;
delete [] pquiz;
pquiz=0;
return 0;
}
If I understand correctly member grades holds the length of the array pointed to by member pquiz. Whenever grades is set pquiz must also reflect new change (old array should be deleted, new one should be created). In constructor must only create the array. In setGrades() must delete old and create new.
Because member pquiz is controlled (or owned) by the class TestScore it's only logical that it should be deleted when object TestScore is deleted (or in our lingo "when it goes out scope"). This is done in class destructor, which you should add to the class.
According to text there should be one more member function, average(), that calculates the average and stores the value in member average. This member should be renamed, for the sake of your sanity.