constructor not Inheriting - c++

I was tryiing to inherit a comstructor from base class to the a derived class which was derived from another derived class of the base class.
but it says " no deafault constructor exists for class Waiverstudents " after inheriting the base class constructor.
class Student
{
private:
string StudentName, StudentID, CGPA , UpcomingSemester , UpcomingSemesterCredits;
public:
Student (string a, string b, string c , string d, string e)
{
StudentName= a;
StudentID=b;
CGPA=c;
UpcomingSemester=d;
UpcomingSemesterCredits=e;
}
string DisplayStudent()
{
cout<<StudentName<<endl<<StudentID<<endl<< CGPA <<endl<< UpcomingSemester <<endl<< UpcomingSemesterCredits;
}
};
class ScholarshipStudents: virtual public Student
{
private:
float ScholarshipPercent = 0.3;
float tution_fee;
public:
ScholarshipStudents(string a, string b, string c , string d, string e) : Student(a,b,c,d,e)
{}
float TutionFee(int a)
{
tution_fee=(a*ScholarshipPercent);
return tution_fee;
}
string DisplayScholarshipStudent()
{
DisplayStudent();
cout<<tution_fee;
}
};
class WaiverStudents: virtual public Student
{
private:
float Waiverpercent = 0.15;
float tution_fee;
public:
WaiverStudents (string a, string b, string c , string d, string e) : Student(a,b,c,d,e)
{}
float WaiverTuitionFee(int a )
{
tution_fee =(a*Waiverpercent);
}
string DisplayWaiverStudent()
{
DisplayStudent();
cout<<tution_fee;
}
};
class SpecialStudents : public WaiverStudents , public ScholarshipStudents
{
public:
SpecialStudents(string a, string b, string c , string d, string e): Student(a,b,c,d,e)
{} //in this line it shows error. " no deafault constructor exists for class Waiverstudents "
string DisplaySpecialStudent()
{
DisplayStudent();
}
};
I tried This
SpecialStudents(string a, string b, string c , string d, string e): ScholarshipStudents(a,b,c,d,e):WaiverStudents(a,b,c,d,e)
same thing happened.
please help me. to overcome the situation. why the I cant inherit the the constructor

There are several problems in your code so I'm going to provide a quick solution to the immediate problem in your question. The problem that you are experiencing is because of the way that virtual inheritance works. In virtual inheritance the most derived type (SpecialStudents in your code) calls the constructor in the base class (Student in your code). It must also call a constructor in each of the other classes it derives from (ScholarshipStudents and WaiverStudents). Since you are only invoking the constructor of SpecialStudents the compiler will implicitly try to invoke the default constructor of all other classes it inherits from and since those constructors do not exist you receive an error.
To fix this you have two options. The first is to explicitly invoke the constructors of each of the classes SpecialStudents and the second provide a default constructor in ScholarshipStudents and WaiverStudents. The most optimal choice in this case it to provide default constructors in those classes but make them protected to prevent them from being called except during the creation of a derived type.
class Student
{
// ... Other code ...
protected:
// Default constructor that handles initialization specific to this class.
Student() = default;
};
class ScholarshipStudents
{
// ... Other code ...
protected:
// Default constructor that handles initialization specific to this class.
ScholarshipStudents() = default;
};
class WaiverStudents
{
// ... Other code ...
protected:
// Default constructor that handles initialization specific to this class.
WaiverStudents() = default;
};
And finally your most derived type only needs to explicitly call the constructor in Student
class SpecialStudents : public WaiverStudents, public ScholarshipStudents
{
public:
SpecialStudents(string a, string b, string c, string d, string e)
: Student(a, b, c, d, e)
{}
};
Please be aware that there are several other problems in your code and the use of virtual inheritance to approach this problem is an incredibly terrible idea. What happens if you add another tuition based fee adjustment? How many different class types will you need to to add to support it. what happens if several more adjustments are added? Now thing about what happens if an existing fee is added or removed from an existing student. Not only will you have to recreate the student but every other reference to that original instance of Student will need to be informed of the change - otherwise they are now working with stale student data.
A rule of thumb in object oriented development is to prefer composition and aggregation over inheritance and in your case a very compelling example of why. You have created multiple derived types to support something that would be much better served as a simple attribute of student - i.e. a list of fee adjustments that can be applied to their tuition. This way when new fees and adjustments need to be applied to the student those pieces of data can be managed in a more focused and cohesive manner.
One way to do this is to start by creating a type that represents a fee adjustment. Something that has a name along with the adjustment itself. We're also going to stop using using namespace std because it's an incredibly bad practice. Instead we'll scope in the names we need via std::.
class FeeAdjustment
{
public:
FeeAdjustment(std::string name, float adjustment)
:
name_(move(name)),
adjustment_(adjustment)
{}
const std::string& Name() const
{
return name_;
}
void Set(float newAdjustment)
{
adjustment_ = newAdjustment;
}
float Get() const
{
return adjustment_;
}
private:
const std::string name_;
float adjustment_ = 0.0f;
};
Now of course you'll need to update the Student class to manage a list of adjustments as well as the overall tuition the student needs to pay. We can do that by adding a couple of new members to Student like so.
float Tuition;
std::vector<FeeAdjustment> TuitionAdjustments;
Now that we have something to track our tuition and keep our list of adjustments in a vector, we'll also want to update the constructor so that it takes the initial tuition fee. We'll also want to update the names of the parameters the constructor takes for clarity.
Student(
std::string studentName,
std::string studentId,
std::string cgpa,
std::string upcomingSemester,
std::string upcomingSemesterCredits,
float initialTution)
:
StudentName(studentName),
StudentID(studentId),
CGPA(cgpa),
UpcomingSemester(upcomingSemester),
UpcomingSemesterCredits(upcomingSemesterCredits),
Tuition(initialTution)
{}
We'll also want to add some new functionality so that we can add a fee adjustment for the student. I'll leave modifying and removing the fees up to you as an exercise.
void AddFeeAdjustment(std::string name, float feeAdjustment)
{
TuitionAdjustments.push_back(FeeAdjustment(name, feeAdjustment));
}
And finally we'll want to update DisplayStudent so that it includes a list of fees along with the adjusted tuition. To do this we we can just iterate over the list of fees and while displaying them create a total amount to be subtracted from the students tuition.
void DisplayStudent() const
{
std::string output;
std::cout
<< StudentName << "\n"
<< StudentID << "\n"
<< CGPA << "\n"
<< UpcomingSemester << "\n"
<< UpcomingSemesterCredits << "\n"
<< "Tuition = " << Tuition << "\n";
float tuitionAdjustments = 0.0f;
for (const auto& adjustmentDetails : TuitionAdjustments)
{
const float adjustment(Tuition * adjustmentDetails.Get());
std::cout
<< "Tution adjustment for " << adjustmentDetails.Name()
<< " = " << std::to_string(Tuition * adjustmentDetails.Get()) << "\n";
tuitionAdjustments += adjustment;
}
std::cout << "Tuition (Adjusted) = " << (Tuition - tuitionAdjustments) << "\n";
}
Now to do some quick validation we'll just create an instance, add some fee adjustments, and display the student.
Student student("Captain Obvlious", "777", "5.0", "Purple", "100", 10000.0f);
student.AddFeeAdjustment("Scholarship", .3f);
student.AddFeeAdjustment("Waiver", .15f);
student.DisplayStudent();
Which gives us the following output:
777
5.0
Purple
100
Tuition = 10000
Tution adjustment for Scholarship = 3000.000000
Tution adjustment for Waiver = 1500.000000
Tuition (Adjusted) = 5500```

Related

C++ implementing derived class from base class by map and using methods from

i am facing issue which i want to create abstract class and 4 subclasses. Abstract class = Entry , and other subclasses are given in the code down.
class entry {
friend ostream &operator<<(ostream &os, const entry &obj);
private:
static constexpr char *def_info = "Undefind";
protected:
string desc;
int ID;
static int counter;
public:
entry() : entry(def_info) {}
entry(string input_s);
void setDesc(string);
string getDesc() const;
int getID() const;
virtual string getContents() const = 0;
virtual void displaying(ostream &os) const = 0;
virtual ~entry() = default;
};
int entry::counter = 0;
entry::entry(string input_s) :
desc{input_s} {
++counter;
ID = counter;
}
ostream &operator<<(ostream &os, const entry &obj) {
os << obj.getContents()<<endl;
obj.displaying(os);
return os;
}
void entry::setDesc(string input) {
desc = input;
}
string entry::getDesc() const {
return desc;
}
int entry::getID() const {
return ID;
}
//PhoneEntry extending the Entry with a phone number
class phone_entry :virtual public entry {
private:
static constexpr char *text = "Undefind";
static constexpr int def_no = 48000000000;
protected:
int phone_number;
public:
phone_entry(string input_s = text, int input = def_no) :
entry(input_s), phone_number(input) {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nPhone number : " << phone_number;
return output.str();
}
virtual ~phone_entry() = default;
};
//EmailEntry extending the Entry with an e-mail addres
class email_entry : virtual public entry {
private:
static constexpr char *def_info = "Undefind";
protected:
string email;
public:
email_entry(string des = def_info, string email_entry = def_info) :
entry(des), email{email_entry} {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nEmail : " << email;
return output.str();
}
virtual ~email_entry() = default;
};
//AddressEntry extending the Entry with an address containing a city, a street and a house number
class address_entry : virtual public entry {
private:
static constexpr char *def_info = "Undefind";
static constexpr int def_no = 0;
protected:
string city;
string street;
int house_number;
public:
address_entry(string des = def_info, string c = def_info, string s = def_info, int hn = def_no) :
entry{des}, city{c}, street{s}, house_number{hn} {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nCity: " << city << "\nStreet: " << street << "\nHouse number: "
<< house_number;
return output.str();
}
virtual ~address_entry() = default;
};
class contact_book : virtual public entry {
static constexpr char *def_info = "Undefind";
private:
map<string,entry *> contacts;
string nick_name;
public:
class error_mesg : public logic_error {
public:
error_mesg(const string message = "NULL") :
logic_error(message) {}
};
contact_book(string e = "undefind") :
entry{def_info},nick_name{e} {}
void add(string a , entry &content){
contacts.insert(make_pair(a,&content));
}
virtual void displaying(ostream &os) const override {
os << "TESTING";
}
};
I want to use contact_book class and use map container to insert the key and values to any of the subclasses like ("cool", new phone_entry("NAME",000000) by using add method that it has two parameters one for the key and other it must have connection to the other classes so i thought that using entry obj will do the job ofc i used pointer in the member because i want to use Polymorphism. also i dont have any idea how i can use the getContencts and it knows from which subclass calling. For example , he asked that the main will look like this :
ContactBook contacts(“My contacts”);
contacts.add(“Johny”, new PhoneEntry(“John Smith”, 100200300));
contacts.add(“Lisa”, new EmailEntry(“Lisa Wood”, “lisa#gmail.com”));
contacts.add(“Andy”, new AddressEntry(“Andrew Fox”, “Warsaw”, “Green St.”, 7));
cout << contacts;
//result (ordered):
//Andrew Fox: Warsaw, Green St. 7 (pos. 3)
//John Smith: phone 100200300 (pos. 1)
//Lisa Wood: e-mail lisa#gmail.com (pos. 2)
try {
cout << contacts[“Andy”].getContents() << endl;
//result:
//Andrew Fox: Warsaw, Green St. 7 (pos. 3)
can you please help me out how to implement them and get what he wants and how & will work on that adding method and new as well in main func.
You are not pretty clear about what your actual problem is – so I'll assume you have trouble getting the desired output for the entire contact book...
First, some other issues, though:
It is meaningless to let contact_book inherit from entry - the book contains entries, it is not one. It seems as if you only inherited to be able to override displaying function to be able to use the already defined operator<< for entry class. But that's a bad reason for inheriting. Instead, you should provide a separate overload of operator<< for your contact book:
std::ostream& operator(std::ostream& s, contact_book const& cb); // coming to later
Then get used to reuse code where appropriate; I assume getContents should output the same string that would be written to std::cout via operator<<. OK, then let's profit from:
std::string entry::getContents()
{
std::ostringstream s;
s << *this;
return s.str();
}
You don't need to have it virtual any more (and shouldn't).
I personally would go with a default for displaying function (that's not a very good name, though, you should prefer imperative forms 'display', perhaps even better: 'printToStream' or just 'printTo'):
void entry::printTo(std::ostream& s)
{
// output members to s
}
Then your inheriting classes could re-use it:
void phone_entry::printTo(std::ostream& s)
{
entry::printTo(s); // use parent's version first to print common data
// now append phone number to s...
}
Users should rather use operator<< instead of printTo function, though. Might be a good idea to have it protected (or even private).
Finally getting back to outputting the contact book:
std::ostream& operator(std::ostream& s, contact_book const& cb)
{
// you want to output every entry? then do so:
for(auto& e : cb.contacts)
{
s << *e.second << std::endl;
// ^^^^^^^ map entries are of type std::pair<key_type const, mapped_type>
// ^ you stored pointers, operator<< accepts reference
}
}
Again, you'd be re-using code already written.
One last note: You are mixing classic initialisation (parentheses) and uniform initialisation (braces), one time even in one single line (email_contact):
entry(des), email{email_entry}
I personally think UI in general has some valid reasoning, the way it was implemented in C++ is broken, though. There are quite a few other issues with, my 'favourite' one is:
std::vector<int> v0{7}; // gives you a vector with 7 elements, all 0!!!
// with classic initialization:
std::vector<int> v1(7); // now clear, you WANT such a vector!
std::vector<int> v2({7}); // now clear, you want initializer list
You now can follow my reasoning or not (others opt for UI nonetheless to profit from the advantages of), but whatever you decide – please do it consistently over the entire file/project!

Understanding OOP Association and Functions (c++)

There's still a whole load of stuff I do not understand about objects and classes in c++, nothing I have read so far has helped me understand any of it and I'm slowly piecing information together from exercises I manage to complete.
Few main points:
When an object is created from a class, how can you access the name of the object in a function in another class? What type of variable is the name of the object stored in? is it even stored anywhere after it's creation?
My manual has an example of creating an association between two classes;
Aggregationclass
{
public:
...
private:
Partclass* partobject_;
...
};
What does this actually mean? Aggregationclass can access the object partobject in partclass? what variables can be read by aggregationclass from the partclass?
Here is a exercise I'm stuck on from my c++ OOP introductionary class, that expects me to utilize association between classes. (7(2/2)/11)
It consists of uneditable Car class;
#include <iostream>
#include <string>
using namespace std;
class Car
{
public:
void Move(int km);
void PrintDrivenKm();
Car(string make, int driven_km);
private:
string make_;
int driven_km_;
};
Car::Car(string make, int driven_km) : make_(make), driven_km_(driven_km)
{
}
void Car::Move(int km)
{
driven_km_ = driven_km_ + km;
cout << "Wroom..." << km << " kilometers driven." << endl;
}
void Car::PrintDrivenKm()
{
cout << make_ << " car has been driven for" << driven_km_ << " km" << endl;
}
What I have made so far(Person class); I have written most of my questions in comments of this section.
class Person //how do I associate Person class with Car class in a way that makes sense?
{
public:
void ChangeCar(string);
Person(string, string);
int DriveCar(int);
private:
Car* make_;
Car* driven_km_;
string name_;
};
Person::Person(string name, string make) //How do I ensure string make == object created from class Car with same name?
{
Person::name_ = name;
Car::make_ = make_;
}
int Person::DriveCar(int x) //Is this the correct way to use a function from another class?
{
Car::Move(x);
}
void Person::ChangeCar(string y) //this function is wrong, how do I create a function that calls for object from another class with the parameter presented in the call for this function (eg. class1 object(ferrari) = class1 object holds the values of object ferrari from class2?)?
{
Car::make_ = y;
}
and an uneditable main();
int main()
{
Car* dx = new Car("Toyota corolla DX", 25000);
Car* ferrari = new Car("Ferrari f50", 1500);
Person* driver = new Person("James", dx);
dx->PrintDrivenKm();
driver->DriveCar(1000);
dx->PrintDrivenKm();
ferrari->PrintDrivenKm();
driver->ChangeCar(ferrari);
driver->DriveCar(20000);
ferrari->PrintDrivenKm();
return 0;
}
disclaimer: the exercise has been translated from another language, in case of spotting a translation error I failed to notice, please do give notice and I will do my best to fix.
Finished exercise; thank you, u/doctorlove for taking the time with your replies, I can with confidence say that I learned a lot!
class Person
{
public:
void ChangeCar(Car * y);
Person(String name, Car * Car);
int DriveCar(int);
private:
Car * Car_;
int x;
string name_;
string y;
};
Person::Person(string name, Car * Car) : name_(name), Car_(Car)
{
Person::name_ = name;
}
int Person::DriveCar(int x)
{
Car_->Move(x);
}
void Person::ChangeCar(Car * y)
{
Car_ = y;
}
Before talking about pointers, look at the Car class:
class Car
{
public:
void Move(int km);
void PrintDrivenKm();
Car(string make, int driven_km);
private:
string make_;
int driven_km_;
};
You can't get to the private stuff from outside. Period.
You can make (or construct) one
Car car("Zoom", 42);
Since we can see what the constructor does
Car::Car(string make, int driven_km) : make_(make), driven_km_(driven_km)
{
}
it's clear it saves away the string and int in the private member variables make_ and driven_km_.
Now we can call the public functions on this instance:
car.PrintDrivenKm();
car.Move(101);
car.PrintDrivenKm();
So, we've made a car and called some functions.
We could make a car pointer and call its functions too. We need to delete stuff otherwise we leak.
Car * car = new Car("Zoom", 42);
car->PrintDrivenKm();
car->Move(101);
car->PrintDrivenKm();
delete car;
Now to your problems.
You have a started writing a Person class which has two (private) cars (pointers) make_ and driven_km_. The constructor Person(string, string); takes two strings, but main doesn't send it two strings:
Car* dx = new Car("Toyota corolla DX", 25000);
// ...
Person* driver = new Person("James", dx);
It will be sent a string and a Car *; something like this
Person(string name, Car *car);
So perhaps it only needs one car (pointer), Car *car_?
Now as for calling your car pointer, Car has Move method; an instance method not a static method, so call it on an instance:
int Person::DriveCar(int x)
{
//Car::Move(x); //no - which car do we move, not a static on ALL cars
car_->Move(x);
}
Now, if the person wants to change car, you made person take a string:
void Person::ChangeCar(string y)
{
//what goes here?
// you want a Car * from a string...
// we did that before
delete car_; //not exception safe, but ...
car_ = new Car(y);
}
Look back at mian:
driver->ChangeCar(ferrari);
so the calling code will try to send a car (pointer) to swap to. So, get the signature right:
void Person::ChangeCar(Car * y)
{
car_ = y;
}
If you owned the pointers, you would need a destructor to tidy up pointers.
Tell whoever set wrote the code in main to delete their pointers!
Edit:
To re-iterate, in any of the Person you can call the methods on the meber variable car_ functions e.g.
void Person::ChangeCar(Car * y)
{
car_ = y;
y->PrintDriveKm(); //call a method on a car pointer.
car_->PrintDriveKm();
}
This is just the same as calling methods on pointers, as mentioned near the top of my answer.
Go back to
Car* dx = new Car("Toyota corolla DX", 25000);
// ...
Person* driver = new Person("James", dx);
From here, in main, you can call
dx->PrintDrivenKm();
From inside the Person constructor,
Person(string name, Car *car) : name_(name), car_(car)
{
}
You can call methods on car (or car_) inside the braces:
Person(string name, Car *car) : name_(name), car_(car)
{
std::cout << "Hello, " << name << '\n';
car_->PrintDrivenKm();
}
Of note: Car:: means something in the class/structr/namespace/scope Car - but you want to call instance methods, so need an instance name. Use -> to all methods on pointers to instances. Use . to call methods on instances.

Class With A Private Member Being A Template With A Base Class Pointer?

Hi I need some clarification on some code since google did not help nor did any of my C++ books. Ok I have a base class,which I derived 2 other classes, but I did not post the code for them here since they don't have anything to do with my question:
ifndef BASEBALLPLAYER_H
#define BASEBALLPLAYER_H
#include <iostream>
using namespace std;
class BaseBallPlayer{ //abstract class meaning no instance can be made for it, which is why we access it via derived classes
//data members
protected:
string name;
int height;
int weight;
public:
BaseBallPlayer();
BaseBallPlayer(string nam, int wight, int hight);
string get_Name();
virtual void print_player()=0; //
virtual void load_player(ifstream & read) = 0; //
virtual ~BaseBallPlayer();
};
Then an ArrayList.h file:
#ifndef ARRAY_LIST_H
#define ARRAY_LIST_H
#include <string>
using namespace std;
const static int MAX_INIT = 99;
template <class elemType>
class ArrayList {
private:
int n_element;
elemType * data;
public:
~ArrayList();
ArrayList(int n = MAX_INIT);
ArrayList(const ArrayList<elemType> &);
const ArrayList<elemType> & operator=(const ArrayList<elemType> &);
void MakeEmpty();
bool IsFull() const;
int LengthIs() const;
void RetrieveItem(elemType &, bool&);
void InsertItem(elemType);
void DeleteItem(elemType);
void ResetList();
bool IsLastItem();
void GetNextItem(elemType &);
};
Now my question lies in this new class, its a standalone class, that I made in the PlayerDatabase.h file:
#ifndef PLAYERDATABASE_H
#define PLAYERDATABASE_H
#include <iostream>
#include "BaseBallPlayer.h"
#include "ArrayList.h"
using namespace std;
class PlayerDatabase{
private:
ArrayList<BaseBallPlayer *> teamArrayList; // I do NOT Understand what this means?
public:
};
#endif
I DO NOT understand what the private member in my PlayerDatabse.h file means or entails? And what can I do with it? My instructor told us to usethat template with a pointer but I didn't have a chance to ask what it does/mean?
So I'm not exactly sure what you end goal is here, but let me take a quick guess at what you might be trying to do:
So you mentioned you have 2 subclasses of BaseBallPlayer, let's say they are MajorLeaguePlayer and MinorLeagePlayer This private Array list teamArrayList can be used to hold any combinations of your base class (BaseBallPlayer -- in your case MajorLeaguePlayer and MinorLeaguePlayer).
You usually want to leave this teamArrayList private so that it will only be safely modified by your public methods. So for example you might want to have a constructor for PlayerDatabase that takes an argument of ArrayList<BaseBallPlayer *>
PlayerDatabase(ArrayList<BaseBallPlayer *> players) {
// set the private teamArray list in the constructor
teamArrayList = players;
}
or you might want to sort the teamArray list based off of one of the properties in the base class BaseBallPlayer
// or another one sorting for weight or name
void sortPlayerListByHeight() {
// sort the private team array list
teamArrayList = ... // sort by height
}
Maybe you want to get the number of players in the list, or find the first or last player in the list. In general it's good practice to use public methods to access/modify private data members (i.e. teamArrayList)
int numberOfPlayersInList() {
return teamArrayList.LengthIs();
}
BaseBallPlayer getFirstPlayerInList() {
return teamArrayList.RetrieveItem.... // get the first item in the list
}
Then from another class you could construct some of your subclass objects and construct your player database:
ArrayList<BaseBallPlayer *> playerList = new ArrayList<>();
playerList.add(new MinorLeagePlayer("minorName", 180,70);
playerList.add(new MajorLeaguePlayer("majorName", 200, 72);
PlayerDatabase db = new PlayerDatabase(playerList);
// now you can do some operations on the PlayerDatabase knowing that the list will contain all objects that can use methods from the Base Class (`BaseBallPlayer`)
db.getFirstPlayerInList().print_player(); // method from your base class implemented in your subclasses
int numberOfPlayers = db.numberOfPlayersInList();
// do something with the number of players in the list
This is pseudo code, but hopefully it will help you get the idea.
Edit related to our comments:
ArrayList<BaseBallPlayer *> *playerList = new ArrayList<BaseBallPlayer *>();
MinorLeaguePlayer *aPlayer = new MinorLeaguePlayer();
playerList->InsertItem(aPlayer);
I've included a couple of simple cout statements in the ArrayList constructor, the MinorLeaguePlayer constructor, and the InsertItem method to output some information when they are called (I'm assuming you already have implementations of these methods):
ArrayList constructor: n_element = n;
cout << "Constructing the arrayList, n_element = " << n_element << endl;
MinorLeaguePlayer constructor: cout << "Constructing a minor league player" << endl;
InsertItem method: cout << "Inserting an item into the ArrayList" << endl;
Here's the output after building and running the above code:
Constructing the arrayList, n_element = 99
Constructing a minor league player
Inserting an item into the ArrayList
Edit 2 related to further comments:
Methods which take a reference to the elemType
Example:
// this will basically just going to "hold" the BaseBallPlayer fetched
// from GetNextItem
BaseBallPlayer *bPlayer;
playerList->GetNextItem(bPlayer);
cout << "Weight after fetching from list = " << bPlayer->weight << endl;
The implementation of GetNextItem is going to look something like this:
void ArrayList<elemType>::GetNextItem(elemType& player) {
// implementation to get the next item in the array list
player = //... set the "NextItem" to the BaseBallPlayer reference we passed into this method
}
Edit 3: print_player() polymorphism:
MinorLeaguePlayer *minPlayer = new MinorLeaguePlayer();
MinorLeaguePlayer *min2Player = new MinorLeaguePlayer();
MajorLeaguePlayer *majPlayer = new MajorLeaguePlayer();
MajorLeaguePlayer *maj2Player = new MajorLeaguePlayer();
playerList->InsertItem(minPlayer);
playerList->InsertItem(min2Player);
playerList->InsertItem(majPlayer);
playerList->InsertItem(maj2Player);
BaseBallPlayer *fetchedPlayer;
for (int i = 0; i < 4; i++) {
playerList->GetNextItem(fetchedPlayer);
fetchedPlayer->print_player();
}
Notice that you have to get the reference to the fetchedPlayer prior to calling the print_player() method on it
playerList->GetNextItem(fetchedPlayer);
fetchedPlayer->print_player();
This is because of the way your GetNextItem method is structured to place the reference to the nextItem in the passed in BaseBallPlayer.
Here's another example where the method would return the BaseBallPlayer instead of setting it by reference:
method stub (in ArrayList):
elemType getNextItemReturn();
for loop:
for (int i = 0; i < 4; i++) {
playerList->getNextItemReturn()->print_player();
}
Here's a link to a quick discussion asking which is more efficient:
Which is more efficient: Return a value vs. Pass by reference?
And the output with the example cout statements:
Constructing the arrayList, n_element = 99
Inserting an item into the ArrayList
Inserting an item into the ArrayList
Inserting an item into the ArrayList
Inserting an item into the ArrayList
Printing From MINOR League Player
Player Name: MinorLeagueName Weight = 22
Printing From MINOR League Player
Player Name: MinorLeagueName Weight = 22
Printing From MAJOR League Player
Player Name: MajorLeaguePlayer Weight = 33
Printing From MAJOR League Player
Player Name: MajorLeaguePlayer Weight = 33
The mock implementations of print_player():
void MinorLeaguePlayer::print_player() {
cout << "Printing From MINOR League Player" << endl;
cout << "Player Name: " << name << " Weight = " << weight << endl;
}
void MajorLeaguePlayer::print_player() {
cout << "Printing From MAJOR League Player" << endl;
cout << "Player Name: " << name << " Weight = " << weight << endl;
}
teamArrayList is a list of pointers to BaseBallPlayer objects. By using pointers, it can by polymorphic -- the pointers can point to any class derived from BaseBallPlayer.
This is the common way to use an abstract base class. You can then use it to call the methods in the BaseBallPlayer class, and the implementations in the appropriate derived classes will be used.

I dont understand what to do in the read() method

This is my c++ homework and i dont really get what they meant by setting the values in the method read().
Question: Create a base class called Athlete that contains 2 member variables for attributes common to all professional athletes: name and annual salary. It should also contain pure virtual method, read(). The method read() is called to read data from the user for setting the values of the attributes.
Here is my header file
#ifndef ATHLETE_H
#define ATHLETE_H
#include <string>
using namespace std;
class Athlete
{
public:
Athlete();
~Athlete();
void setName(string name);
string getName() const;
void setSalary(double salary);
double getSalary() const;
virtual void display() const;
virtual void read(string name, double salary) const;
private:
string name;
double salary;
};
#endif
And my cpp
#include "Athlete.h"
#include <iostream>
Athlete::Athlete() {}
Athlete::~Athlete() {}
string Athlete::getName() const { return this->name; }
void Athlete::setName(string name) {
this->name = name;
}
double Athlete::getSalary() const {
return this->salary;
}
void Athlete::setSalary(double salary) {
this->salary = salary;
}
void Athlete::read(string name, double salary) const {
Athlete* temp = new Athlete();
temp->setName(name);
temp->setSalary(salary);
}
void Athlete::display() const {
cout << "Name: " << this->getName() << endl;
cout << "Salary: " << this->getSalary() << endl;
}
I tried to use the setter methods in read but theres an error.
I think you misread the question. It says that the read() method should read the data from the user. Usually it means read from the standard input. Afterwards, the method should set the values of the attributes for this specific athlete. Meaning, that the entered values relate to this specific object. Not for something new and temporary.
Pulling everything together is may look like the following:
void Athlete::read()
{
string name;
double salary;
std::cout << "Please enter the athlete name:";
std::cin >> name;
std::cout << "Please enter the athlete salary:";
std::cin >> salary;
setName(name);
setSalary(salary);
}
The thing you've missed is that read is supposed to be a pure virtual function. This means that you should not actually implement it, instead you should declare it as:
virtual void read(string name, double salary) = 0;
This means that the Athlete class cannot actually be instantiated (it's called an absract class), instead it will be used as a base class and derived classes would be required to override the read method. If they don't override the method they will themselves be abstract and cannot be instantiated.
You are not required to implement the read method as a method of Athlete once you declared it as pure virtual. It only need to be implemented as a method in the derived class(es).
Also as the method in the derived class is supposed to modify the object the method cannot be const declared (as shown above).

C++: how to make getters and setters work with an empty constructor

First of all, I have only learned a little bit of Java before. It's been only a few days since I started getting friendly with C++ so please don't take this question so basic and please don't degrade my question.
I made a simple source code as follows:
#include <iostream>
using namespace std;
class Car {
public:
void setBrand(string name);
void setPrice(double price);
string getBrand();
double getPrice();
Car();
Car(string name);
Car(string name, double price);
private:
string name;
double price;
};
Car::Car() {
}
Car::Car(string name) {
name = name;
}
Car::Car(string name, double price) {
name = name;
price = price;
}
void Car::setBrand(string name) {
name = name;
}
void Car::setPrice(double price) {
price = price;
}
string Car::getBrand(void) {
return name;
}
double Car::getPrice(void) {
return price;
}
int main() {
Car car;
car.setBrand("Nissan");
car.setPrice(30000);
cout << "Brand: " << car.getBrand() << endl;
cout << "Price: " << car.getPrice() << endl;
return 0;
}
I wanted to make a code that creates an empty instance of a class called Car, set the field values later and print them out on the console.
The code did not make any errors during the compile, but the result I see was totally different from what I expected. It didn't show the brand name and the price was looking even weird, as follows.
Brand:
Price: 6.95322e-310
Somebody help me out! Thank you very much indeed in advance.
The problem you have is that you override the member names with function parameters. You can use this-> to make it explicit or name the member differently.
For example:
void Car::setBrand(string name) {
this->name = name;
}
Or:
void Car::setBrand(string new_name) {
name = new_name;
}
In your constructor and setters, you make no differentiation between the local parameter and the class member.
name = name;
Both the function parameter and the class member are called name. Currently the compiler is assigning the parameter value to itself, and not affecting the class member at all. This is because the function parameter is in a more immediate scope.
Possible solutions:
Specify this when referring to the class member: this->name = name;.
Rename the function parameter: name = _name;.
For the constructor, use initializer lists:
Car::Car(string name, double price)
: name(name)
, price(price)
{ }
There's too much wrong with your code to describe it in prose, so let me present a fixed implementation, and I leave it to you to spot the difference:
#include <string>
class Car
{
private:
static constexpr double kNoPrice = -1.0;
static constexpr const char* kNoName = "[no name]";
public:
// Main constructor: constructs a car with the given name and price.
Car(std::string name, double price)
: name_(std::move(name))
, price_(price)
{}
// Convenience constructors:
Car() : Car(kNoName, kNoPrice) {}
Car(std::string name) : Car(std::move(name), kNoPrice) {}
// Accessors:
const std::string& getBrand() const { return name_; }
void setBrand(std::string name) { name_ = std::move(name); }
double getPrice() const { return price_; }
void setPrice(double price) { price_ = price; }
private:
std::string name;
double price;
};
Some random notes, in no particular order:
Use correct names. It's std::string, not string, mate or buddy. Never ever be abusing namespace std.
Include headers for external names that you need.
Reading uninitialized values is undefined behaviour, so none of your constructors should leave fields uninitialized (like price_).
Give private members consistent names (e.g. foo_ in my example).
Accessors should be const-correct.
Convenience constructors should delegate to one single work-horse constructor.
Pick sensible defaults for initial values of defaulted fields and make them discoverable.
Use move semantics when taking ownership of dynamically managed data (strings, dynamic containers, etc.).