Passing Array of objects to same class C++ - c++

Question : Declare a class named ‘StudentRec’ with three private members: ‘enrolNo’ of type int, ‘CGPA’ of type float and ‘branch’ of type string. Declare an array of objects named ‘Student’ of size 5 of class ‘StudentRec’. Write public member functions: (i) void sort (StudentRec Student[], int N ) to sort the data in ascending order with respect to ‘CGPA’ and (ii) void print (StudentRec Student[], int N ) to display the sorted and unsorted students’ records. Write main to test these member functions.
Doubt : The sorting part I will do later. My doubt is if in the below code(2nd last line ) Student[5].print(Student, N ); is correct way to call the function print? How else can this function be called via array of objects Also Student[0].print(Student, N ) gives correct output. Why ?
#include<iostream>
#include<cstring>
using namespace std;
class StudentRec
{
private:
int enrolNo;
float CGPA;
string branch;
public:
void assign()
{
cin>>enrolNo>>CGPA>>branch;
}
void sort (StudentRec Student[], int N );
void print(StudentRec Student[], int N )
{
int i;
for(i=0; i<5; i++)
{
cout<<"Student"<<" "<<i<<" " ;
cout<<Student[i].enrolNo<<" "<<Student[i].CGPA<<" "<<Student[i].branch<<endl;
}
}
};
int main()
{
StudentRec Student[5];
int i,N=5;
for(i=0; i<5; i++)
Student[i].assign();
Student[5].print(Student, N );
return 0;
}

As has been pointed out, Student[5].print(Student, N ); invokes undefined behavior as there is no Student[5]. However, your implementation of print doesn't actually use the object it is invoked on, so this is probably why this works in practice.
To give your program a somewhat reasonable design while keeping as close to the assignment as possible, you can declare the functions static:
static void print(StudentRec Student[], int N );
This means that, while the functions are declared inside the class and have access to private members of objects of the class, they don't rely on any concrete object to be invoked. You can then use them like this:
StudentRec::print(Student, N);
On a side note, your implementation of print doesn't actually use the parameter N.

Related

How to create objects outside functions with polymorphism?

I want to use polymorphism and create objects outside of main or any other function so that the functions are independent of the type of the objects I have. My code is as follows:
The main class:
class load{ //Main class
protected:
static load **L;
static int n, n1;
public:
load(){};
virtual float getpower()=0;
static int getn();
static load ** getL();
};
load **load::L;
int load::n;
int load::n1;
int load::getn(){
return n;
}
load** load::getL(){
return L;
}
The child class:
class load1:public load{
private:
float power;
public:
load1();
load1(int s);
void createUnits1();
float getpower();
}l1(0); //Object creation
load1::load1(int s){
createUnits1();
}
void load1::createUnits1(){
cout<<"Give the number of type 1 objects: "<<endl;
cin>>n1;
for (int i=0;i<n1;i++){
load1 temp; //Run default constructor
}
}
load1::load1(){
cout<<"Give the power of the device: "<<endl;
cin>>power;
n++;
if (n==1){
L=(load **)malloc(n*sizeof(load *));
}
else {
L=(load **)realloc(L,n*sizeof(load *));
}
L[n-1]=this;
}
float load1::getpower(){
return power;
}
The function of calculation:
float get_total_P(load **l, int num){
float tot_power=0;
for(int i=0;i<num;i++){
tot_power+=l[i]->getpower();
}
return tot_power;
}
My main function:
int main() {
load **l;
int num;
num=load::getn();
l=load::getL();
float total_P=get_total_P(l, num);
cout<<total_P;
return 0;
}
The upper code produces a segmentation fault but I can't see the reason why. The segmentation fault is on the line
tot_power+=l[i]->getpower();
So I guess my way of creating objects is wrong. Is there a better way to do this?
The reason for your segfault, is that l doesn't point to anything valid !
In main() you initialise l with load::getL(). But this function only returns the load::L which has the same type and was defined as static in your load class but was never initialized.
You have coded in your derived class load1 some initialisation code for L, but it is never invoqued in main().
Your code has also some severe design issues:
It's not advised to use malloc() and realloc() in C++ code. If you create an object in C++ use new. If you want some dynamic array, use vectors.
You could get L and hence l initialized if you'd create some load1 objects before calling getL(). But due to your realloc, l would then risk to point to an obsolete thus invalid address, if you would create any other load1 object before calling get_total().
It's bad practice and terrible design to request user input in a constructor. The constructor is meant to cosntruct an object with the parameters you give him when you call him. Imagine the user would give an invalid parameter ? The user would be asked for input whenever a load1 object is constucted. Even for temporary variables, not even speaking from the effect when you'd write load1 a[10];

C++ Implementing Functions that don't utilize global declarations

My code is already working, seen here: http://pastebin.com/mekKRQkG
Right now, my functions work but utilizing information that I've declared globally, I guess, and I want to convert them so that they are in the format as seen on lines 11-15, but I'm unsure of how to convert them to do so. Simply put, I'm trying to convert my function of
"void add_county_election_file"
to be in the format of
"void add_county_election_file(const string, const vector &, const vector &, const vector &, const vector &)"
and I have no idea where to begin or how to even start.
Could someone please help me out and show me how I'd do this for the first function, so I can implement it across the board?
Thanks guys!
Your function declaration should look something like this:
void add_county_election_file(const string, vector<int>&, vector<string>..);
Make sure that your argument list for the vector template is correct(that's the type you put between <>)
Then match the implementation of you function to the declaration:
void add_county_election_file(const string, vector<int>&, vector<string>..){...}
Now call your function with apppropriate arguemtns in main:
string s;
vector<int> arg;
vector<string> sv;
void someFunction (s, arg, sv ...);
I think you are doing correct as the function you have declared
void add_county_election_file(const string, vector<int>&, vector<int>&,..);
so you just have to call the above function with the required arguments, as right now you are not passing the argument and your current definition doesn't accepts any arguments.
And as a good practice, in your int main() function you can use switch rather than going for if else.
Store your variables and functions in a class, overload operators and create functions to access these variables.
Declare all variables in int main() and set parameters to be passed into each function e.g.
void print_results() is modified to become
void print_results(std::vector<int> vec, int nCount, etc..)
Similar to the first one, create a struct to hold all data members, then pass the struct(by ref) into each function.
struct CountryTracker
{
std::vector<int> ID;
std::string name;
//etc...
}
`void print_results(CountryTracker& Obj) //pass single struct into functions`
The OOP way to do this is to create a class called perhaps ElectionInfo, where:
These would be its member fields:
vector <string> countyNameVector;
vector <int> countyNCount;
vector <int> countyFCount;
vector <int> countyOCount;
int NCount;
int FCount;
int OCount;
int NTotal;
int FTotal;
int OTotal;
and these would be its member functions:
void add_county_election_file(const string);
void search_county(const string);
void print_results();
This way you don't have to pass the references to the vectors around at all, instead you can just do:
ElectionInfo an_elect_info;
char selection = get_menu_choice();
// some if-statements to decide which of the following to call:
an_elect_info.add_county_election_file(county_name);
an_elect_info.search_county(county_name);
an_elect_info.print_results();
But if you'd prefer to stay with the current functional approach:
Declare and initialize the following inside your main method:
vector <string> countyNameVector;
vector <int> countyNCount;
vector <int> countyFCount;
vector <int> countyOCount;
int NCount;
int FCount;
int OCount;
int NTotal;
int FTotal;
int OTotal;
The syntax for the commented out function declarations should be tweaked to look like this:
void add_county_election_file(const string, vector<string>&, vector<int>&, vector<int&, vector<int>&);
(Of course, the definition should follow suit)
You would invoke it like this:
add_county_election_file(countyname, countyNameVector, countyNCount, countyFCount, countyOCount);
Objects are automatically passed-by-reference.
The basic process of refactoring should at the first step involve only code grouping and placement and should only minimally involve writing new logic. Using this as a principle you can go about modifying the code in the following way at first.
string ReadInputString(const char* title)
{
string s
cout << title;
cin >> s;
}
void add_county_election_file(const std::string& filename
, std::vector<string>& countyNameVector
, std::vector<int>& countyNCount
, std::vector<int>& countyFCount
, std::vector<int>& countyOCount
)
{
int NCount = 0;
int FCount = 0;
int OCount = 0;
int NTotal = 0;
int FTotal = 0;
int OTotal = 0;
char vote;
std::ifstream input((filename).c_str());
string countyName;
if(input.is_open())
{
input >> countyName;
countyNameVector.push_back(countyName);
while(input >> vote)
{
if(vote == 'N' || vote == 'n')
{
NCount = NCount + 1;
}
else if(vote == 'F' || vote == 'f')
{
FCount = FCount + 1;
}
else
{
OCount = OCount + 1;
}
}
countyNCount.push_back(NCount);
countyFCount.push_back(FCount);
countyOCount.push_back(OCount);
}
cout << countyName << endl;
}
void add_county_election_file()
{
string fn = ReadInputString("Enter the county file to process: ");
add_county_election_file(fn,g_countyNameVector,g_countyNCount,g_countyFCount,g_countyOCount);
}
As you can see I have just extracted your code and moved them to individual functions and changed names to make some significance. Like in the function ReadInputString - the line "cin >> s" was originally "cin >> filename". The abstract name "s" is to signify that the ReadInputString has no knowledge or doesn't care what the semantic meaning of the string it is reading from console.
In order to not change your main function - I have added a overloaded add_county_election_file that calls one function followed by another. The idea is that you should keep something unchanged and change others (for good) and then alternate if need be.
And I have changed names of your global variable to differentiate them from the local variable using "g_" - the point is that "g_" should only be found at very few places in your code.

C++ static object Class function

Some code:
Please see the class myClass below . it has a constructor and a public recursive function find. Please see code:
#include <iostream>
using namespace std;
class myClass{
public:
myClass() {
//do stuff
}
int find(int i) {
static int j = 10;
if (i > 15)
return i;
j = j + 1;
return i * find(j + 1);
}
};
int main()
{
myClass mC1 ,mC2;
cout<< " 1.... return value = "<< mC1.find(10);
cout<< " \n 2... return value = "<< mC2.find(10);
return 1;
}
output:
1.... return value = 5241600
2.... return value = 170
The above progemn has a class myclass having a function find .. "find" function has a variabe . This is static which is required as i wanted a recursive function . Problem is static varible has life of a program & binded to class .
However I want the static to be object specfic and not class scope . I wanted both the function calls to return me same value .
Simply put , how to make a static varable in a class function , to be per object and not for whole class...
Do you need a member variable?
Hope the following code helps.
Best regards
Sam
class myClass{
public
myClass() {
m_j = 10;
}
private:
int m_j; // private member variable for find algorithm;
int find(int i) {
if(i>15)
return i;
m_j= m_j+1;
return i * find(m_j+1);
}
};
If you want a per object variable you need to make it a member of the respective object. There is no way to declare a variable inside a function to be specific to objects. The way you use use static member could be changed to be non-static anyway, i.e., you would get the necessary context: Make the function non-static and store the data in the object as needed.
That said, just because a function is recursive doesn't mean that it needs any sort of static context. Normally, all the necessary context is passed to the recursive function as parameters in which case the system keeps the necessary state on the stack. Since the stack is relatively limited in size you want to make sure that you don't need too much context in recursive functions with deep call stack.
Since you probably don't want to require the user to pass in some internal context, the find() function in the the interface would probably just delegate to the recursive function providing the necessary context. For example:
int find(int j, int i) {
if (15 < i) {
return i;
}
++j;
return i * find(j, j + 1);
}
int find(int value) {
return find(10, value);
}
(I'm not sure if I got the desired logic right because I didn't quite get what the function is meant to do...).

How can I generate random int numbers within a set range (without duplicates!) within a class constructor?

I am self-learning C++ from a text book and I have a problem to solve, outlined below.
I have the following class structure:
#include <iostream>
#include <cstdio>
#include <ctime>
using namespace std;
class classroom{
char name[25];
int student_id;
float grades[10];
float average;
int num_tests;
float letter_grade;
public:
void enter_name_id(void);
void enter_grade(void);
void average_grades(void);
void letter_grades(void);
void output_name_id_grade(void);
classroom();
};
And I have the following Constructor for the above class:
classroom::classroom(){
int i;
srand((unsigned)time(0));
int random_integer=0;
random_integer = (rand()%5) + (rand()%5);
num_tests=0;
average=0.0;
for(i=0;i<10;i++){
grades[i]=0.0;
}
for(i=0;i<27;i++){
name[i]='-';
}
cout<<"\n*****************Finished*****************";
}
There will be 3 students of this class structure declared in the main:
int main()
{
classroom students[3];
//and so...
}
I need to generate a unique student ID for each student in the constructor within a range of values, say, 0 to 10.
I have copied the following code snippet into the constructor. It generates my random number for me within the desired range:
srand((unsigned)time(0));
int random_integer=0;
random_integer = (rand()%5) + (rand()%5);
The problem is that I need to get rid of any duplicates within the range of random numbers that are generated.
Why does the number need to be random? Can't you just use a static int that gets incremented every time you need to generate a new student number?
Simply have a vector with all possible student ids. in your case 0..Range.
do a random_shuffle and pick the first three ids and assign them
I have added a working solution.
//Only have one instance of this class.
class IdMgr
{
std::vector<int> mIds;
int mCurrentId;
public:
IdMgr( int Max )
{
for ( int i = 0 ; i <= Max; ++i )
mIds.push_back( i );
std::random_shuffle( mIds.begin() , mIds.end() );
mCurrentId = 0;
}
//Call this function from your class constructor
int GetNextId()
{
return mIds[ mCurrentId++];
}
};
One way to do this is to use what is called a static member variable. Usually, each object gets its own copy of the member variables. In your code, each student will have his own copy of name[25], student_id, etc. But what you want, is something that will be shared between each instance of the class (each of the elements in classroom students[3] are instances of the classroom class.)
Here are some notes on static member variables. Note that they present a solution to a very similar problem -- they assign unique IDs to each class instance. The only difference between what they present here and what you ask for is that you ask for it to be randomized, instead of consecutive.
So instead of a static member variable keeping track of one number (the last one assigned), you will want your static member variable to keep track of all of the previously assigned ids. A std.vector or simple int array should work.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <vector>
using namespace std;
class classroom{
char name[25];
int student_id;
float grades[10];
float average;
int num_tests;
float letter_grade;
static vector<int> used;
public:
void enter_name_id(void);
void enter_grade(void);
void average_grades(void);
void letter_grades(void);
void output_name_id_grade(void);
classroom();
};
vector<int> classroom::used = vector<int>();
classroom::classroom(){
int i;
int random_integer=0;
bool rand_ok;
do
{
// Generate Random Integer
random_integer = (rand()%5) + (rand()%5);
//cout << "Generated: " << random_integer << endl;
rand_ok = true;
for(i=0; i<used.size(); i++)
{
if(used[i] == random_integer){ rand_ok = false; break; }
}
} while (rand_ok == false);
// If we get here, random_integer is not in the used vector
// therefore accept and store as student_id
student_id = random_integer;
// ... and update used vector
used.push_back(student_id);
num_tests=0;
average=0.0;
for(i=0;i<10;i++){
grades[i]=0.0;
}
for(i=0;i<27;i++){
name[i]='-';
}
cout<<"*****************Finished*****************\n";
}
int main()
{
// You should only seed the RNG once
srand((unsigned)time(0));
classroom students[3];
}
The above code is one way you might do it, by storing the used student ids in a vector, and then every time you create a new student, ensure the randomly generated id doesn't match an already assigned ID.
One other note, you should only seed the random number generator once (especially if your seed is the time). Since you were seeding it 3 times in such a short time, the random numbers being produced were the same.
For all those that want to know the solution to my problem of creating a unique id for each instance of a class, here it is:
class classroom{
char name[25];
int student_id;
float grades[10];
float average;
int num_tests;
float letter_grade;
**static int next_student_id;**
public:
void enter_name_id(void);
void enter_grade(void);
void average_grades(void);
void letter_grades(void);
void output_name_id_grade(void);
classroom();
};
**int classroom::next_student_id=1;**
Notice, the new member: static int next_student_id has been created and used in the constructor, it has also been initialized outside of the class structure.
In the constructor I simply used the following code:
student_id=next_student_id++;
This code produced unique consecutive numbers for each instance of the Class classroom structure;
Please note I am aware that Class classroom is not an ideal name as it conflicts with the name of class, but I used this as I copied the basic naming from a text book question!
I have concluded that Alan's answer above helped me the most and provided me with the most simple solution.And so Alan therefore gets a tick from me.
I would like to thank Jedwards also, your answer if pursued could of also been an alternative solution... but as it turns out, using a static int was the key and generating random numbers and creating vectors was not necessary.
And thank you also parapura rajkumar and other contributors

Problem passing a list of objects to another class, C++

Below I have written a sample program that I have written to learn about passing a list of objects to another class. I talk about the problems I am having below.
#include <iostream>
#include <vector>
using namespace std;
class Integer_Class
{
int var;
public:
Integer_Class(const int& varin) : var(varin) {}
int get_var() { return var; }
};
class Contains_List
{
typedef Integer_Class* Integer_Class_Star;
Integer_Class_Star list;
public:
Contains_List(const Integer_Class_Star& listin) : list(listin) {}
Integer_Class* get_list() { return list; }
};
int main (int argc, char * const argv[])
{
// Create a vector to contain a list of integers.
vector<Integer_Class> list;
for(int i = 0; i < 10; i++)
{
Integer_Class temp_int(i);
list.push_back(temp_int);
}
This is where the errors start occuring. Could someone please look at the second class definition and the code below and shed some light on what I'm doing wrong. Thank you so much, as always!
// Import this list as an object into another object.
Contains_List final(list);
// Output the elements of the list by accessing it through the secondary object.
for(int i = 0; i < 10; i++)
{
cout << final.get_list()[i].get_var();
}
return 0;
}
You don't mention what sort of errors you are getting, but one very obvious problem with your code is that the constructor for Contains_List expects a pointer to Integer_Class while the parameter you are sending it (list) is of type vector<Integer_Class>.
A vector is not the same as an array, so you cannot pass it as pointer to the type it contains. Either change your constructor to accept a vector or pointer/reference to vector, or change the code that is causing you problems so that it sends it a pointer to an array.
The 'Contains_List' constructor takes in an 'Integer_Class*'
You declare 'list' to be of type 'vector', yet you pass it to the the 'Contians_List' constructor. You should change the 'Contains_List' class so that it holds a vector instead of an Integer_List array. The two are not interchangeable.
You could also change the vector to be an array of Integer_List's instead, if you so wished.