Problem constructing a base class from within a subclass constructor - c++

I have 2 classes. Since Doctor will be considered as Employee, I should be using Employee class functions in Doctor class. Only extra thing that Doctor class has is TITLE. Basically, What I tried is I wanted to send value to Doctor's constructor,set title then send remained value to Employee's class ;however, I could not. This is what I have done so far,
employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
class Employee {
private:
int ID;
char *firstname;
char *lastname;
int telno;
char *adress;
char *mail;
int salary;
public:
Employee();
Employee(int,char *,char*,int,char*,char*,int);
char* getfmame();
char* getlname();
char* getadress();
char* getmail();
int getID();
int gettel();
int getsalary();
void printall();
};
#endif
Employee.cpp
#include <iostream>
#include "employee.h"
using namespace std;
Employee::Employee() {
firstname = "Empty";
ID=0;
firstname="Empty";
lastname="Empty";
telno=0;
adress="Empty";
mail="Empty";
salary=0;
}
Employee::Employee(int id,char * first,char* last,int tell,char* adres,char* email,int salar){
ID=id;
firstname=first;
lastname=last;
telno=tell;
adress=adres;
mail=email;
salary=salar;
}
char* Employee::getfmame(){ return firstname; }
char* Employee::getlname(){ return lastname; }
char* Employee::getadress(){ return adress; }
char* Employee::getmail(){ return mail; }
int Employee::getID(){ return ID; }
int Employee::gettel(){ return telno; }
int Employee::getsalary(){ return salary; }
void Employee::printall(){
cout<<endl<<"EMLOYEE INFORMATION"<<endl<<"------------------"<<endl;
cout<<endl<<"ID :"<<ID<<endl<<"FIRST NAME: "<< firstname <<endl<<"LAST NAME: "<< lastname << endl << "TELEPHONE NUMBER: "<<telno<<endl<<"ADRESS: "<<adress<<endl<<"MAIL: "<<mail<<endl<<"SALARY: "<<salary<<endl;
}
Doctor.h
#ifndef DOCTOR_H
#define DOCTOR_H
#include "Employee.h"
using namespace std;
class Doctor :Employee {
public:
enum title {Intern=0,Practitioner=1,Assistant=2,Specialist=3,Docent=4,Professor=5,None=6};
Doctor();
Doctor(title a,int id,char * first,char* last,int tell,char* adres,char* email,int salar);
};
#endif
Doctor.cpp
#include <iostream>
#include "Doctor.h"
#include "Employee.h"
using namespace std;
Doctor::Doctor() {
title tit = None ;
}
Doctor::Doctor(title a,int id,char * first,char* last,int tell,char* adres,char* email,int salar) {
title tit=a;
Employee(id,first,last, tell,adres,email,salar);
printall();
cout<<"typed";
}
Main.cpp
#include <iostream>
#include "employee.h"
#include "doctor.h"
using namespace std;
int main(){
Doctor a=Doctor(Doctor::None,12,"a","b",0550550505,"8424 str nu:5","#hotmail",5000);
return 0;
}

Subclass construction in C++ works so that the base class object must be constructed when the subclass' constructor body is executed:
class A {
/* etc. etc. */
public:
void do_stuff();
};
class B : public A {
B() {
// at this point, an A has already been constructed!
A::do_stuff();
}
};
Note that in this example, since we haven't chosen an explicit constructor for the A instance, the default constructor, A::A(), will be used; and if that constructor is unavailable - we get a compilation error. The fact that a constructor for A has been called is what allows us to then use methods of class A - like A::do_stuff() in the example above.
But - how can we specify a different constructor before the body of the B constructor? Or in your case, how can we use the appropriate constructor for Employee before the body of the Doctor constructor?
The answer was suggested by #user4581301: You need to use an member initializer list. Initializations/constructions on this list are performed before the body, and may include the underlying class. I'll demonstrate with a simplified example. Let's suppose an Employee only has an id and a Doctor only has an additional title.
class Employee {
protected:
int id_;
public:
Employee(int id) : id_(id) { };
int id() const { return id_; }
};
class Doctor : public Employee {
protected:
std::string title_;
public:
Doctor(int id, std::string title) : Employee(id), title_(title) { };
const std::string& title() const { return title_; }
};
So, when a Doctor is being constructed, it constructs its underlying Employee instance using the id it got. The constructor body is used for more complex code beyond simple member initializations.
PS:
You might want to initialize the title_ member with std::move(title) rather than just title, see this question for details.
It's confusing when a constructor has more than two or three parameters with compatible types - users are likely to confuse them with each other. You might consider default values for most fields and setting them after construction, or alternatively, using a builder pattern.
address, with two d's, not adress.
Unless you plan on editing char* fields in-place, use const char *.
They way you've written your classes, Doctor methods would not have write acesss to Employee methods; make sure that's what you intended.
I have some other nitpicks but I'll stop now...

Related

How to push objects to a static vector while in the contructor of a class in C++

I need to get in a vector the names of some cities as soon as they are created... In order to accomplish that I created a static vector for the class City, however when I try to compile my code I get the error
error: lvalue required as unary '&' operand
this->cities.push_back(&this);
^~~~
What am I doing wrong?
My code is the following...
#include <iostream>
#include <ctime>
#include <vector>
using namespace std;
class City
{
private:
string name;
static vector<City *> cities;
public:
string getName() { return name; }
City(string name) : name{name}
{
this->cities.push_back(&this);
};
~City(){};
} hongKong{"Hong Kong"}, bangkok{"Bangkok"}, macau{"Macau"}, singapura{"Singapura"}, londres{"Londres"}, paris{"Paris"}, dubai{"Dubai"}, delhi{"Delhi"}, istambul{"Istambul"}, kuala{"Kuala"}, lumpur{"Lumpur"}, novaIorque{"Nova Iorque"}, antalya{"Antalya"}, mumbai{"Mumbai"}, shenzen{"Shenzen"}, phuket{"Phuket"};
int main()
{
}
this is already a City* pointer, so drop the & from &this.
Also, don't forget to actually define the static vector object.
Also, you should account for the class' copy/move constructors and destructor, to make sure you don't miss adding pointers, or leave behind dangling pointers.
Try this:
#include <iostream>
#include <ctime>
#include <vector>
using namespace std;
class City
{
private:
string name;
static vector<City *> cities;
public:
string getName() { return name; }
City(string name) : name{name}
{
cities.push_back(this);
}
City(const City &src) : name{src.name}
{
cities.push_back(this);
}
City(City &&src) : name{std::move(src.name)}
{
cities.push_back(this);
}
~City()
{
cities.erase(std::find(cities.begin(), cities.end(), this));
}
};
vector<City *> City::cities;
City hongKong{"Hong Kong"}, bangkok{"Bangkok"}, macau{"Macau"}, singapura{"Singapura"}, londres{"Londres"}, paris{"Paris"}, dubai{"Dubai"}, delhi{"Delhi"}, istambul{"Istambul"}, kuala{"Kuala"}, lumpur{"Lumpur"}, novaIorque{"Nova Iorque"}, antalya{"Antalya"}, mumbai{"Mumbai"}, shenzen{"Shenzen"}, phuket{"Phuket"};
int main()
{
}

How can i access to any data that is in private section of class?

#include <iostream>
#include <vector>
using namespace std;
class Test
{
private:
int ID;
string name;
public:
Test(int ID, string name);
};
Test::Test(int ID, string name)
{
this->ID = ID;
this->name = name;
}
int main()
{
vector<Test *> test_vect;
Test *ptr = new Test(100, "John");
test_vect.push_back(ptr);
cout << ptr->ID << endl;
return 0;
}
This is a simple code I'm trying.
I want to access to the data that I stored in vector.
I thought it would be accessible by using -> just like vector of struct but I can't. So I want to know how to load the data in class.
In addition, I thought sending data to heap section using new would make it accessible at any time I want regardless of whether it is private or public, but it seems like it is not possible.
Can you explain how it works?
(I don't even fully understand how class work, so detailed explanation would be very appreciated. Thx!)
A private variable cannot be accessed by code outside the class definition. (There are exceptions with friend)
ptr->ID does not work because main is outside the class definition.
This can be fixed by using a getter method.
#include <iostream>
#include <vector>
using namespace std;
class Test
{
private:
int _ID;
string _name;
public:
int ID() {return _ID;}
string name() {return _name;}
Test(int param_ID, string param_name);
};
Test::Test(int param_ID, string param_name)
{
_ID = param_ID;
_name = param_name;
}
int main()
{
vector<Test *> test_vect;
Test *ptr = new Test(100, "John");
test_vect.push_back(ptr);
cout << ptr->ID() << endl;
return 0;
}
The above example shows the getter methods ID() and name() which return the data members _ID and _name respectively.
ID() is allowed to access _ID because ID() is part of the class definition. name() is allowed to access _name because name() is part of the class definition.
Note: I would still consider this code to be flawed because it creates a new object on the heap, but does not delete it. You should also look up the keywords new and delete to see how they operate together.

Constructor with string (using char array) parameter

Just to make everyone aware. I have to use char array for strings, this is homework and has to be done that way. Also the classes are made on purporse.
I'm supposed to read a fish' name via my Fish class, which is a subclass of Animal class. If the input length is more than 0, then I'll run the constructor with the char array parameter and update the "fishname" inside Fish class. If not, I'll run the constructor without parameter (Fish() constructor).
My questions:
Right now it gives me the option to write in an input, I do that - it crashes. It is the Fish object causing it, but don't know why. How come?
How would I transport the data that I'll get into "fishname" in the Fish data, over to "name" in the Animal class?
So this is what I have made so far, but it only crashes after input.
#include
using namespace std;
#include <iostream>
using namespace std;
class Animal {
private:
char* name;
public:
Animal() { strcpy(name, ""); } // Constructors that set name to nothing
void writeName() { cout << name; } // Function to read an animal's name
};
class Fish : public Animal {
private:
char* fishname;
public:
Fish() {}
Fish(const char* name) { strcpy(fishname, name); }
};
int main() {
char fishname[20];
cout << "Read fish's name: "; cin.ignore();
cin.getline(fishname, 20);
if(strlen(fishname) > 0) Fish f1(fishname);
else Fish f1;
return 0;
}
About the best you can do, short of implementing a lot of the functionality of std::string is to use a fixed size char array. This is not generally a good practice. I would not usually do this, but I will take pity.
#include <iostream>
#include <cassert>
using namespace std; // NEVER write this in a header file. Just saying.
class Animal {
public:
static const int max_name = 128;
Animal() {
name[0] = 0;
}
void writeName() { cout << name; } // Function to read an animal's name
private:
char name[max_name];
};
class Fish : public Animal {
private:
char fishname[Animal::max_name];
public:
Fish() {
fishname[0] = 0;
}
Fish(const char* name) {
assert(strlen(name) < Animal::max_name);
strcpy(fishname, name);
}
};

What is wrong? - Composition compile error (with family+person classes example)

I got two classes, one named Person that I checked is working (I can create objects of that class so the problem should not be here).
I then have another class called Family with composition from Person:
Family.h
#include "Person.h"
class Family
{
public:
Family();
void printFamily();
private:
Person dad_();
Person mum_();
Person son_();
Person daughter_();
};
Family.cpp
#include "Family.h"
Family::Family()
{
}
void printFamily()
{
dad_.printAll();
mum_.printAll();
son_.printAll();
daughter_.printAll();
//printAll() is a function in the Person class that worked when
//I tested it earlier with only the person class
}
But when i try to compile this I get an error:
left of '.printAll' must have class/struct/union
'son_' : undeclared identifier
This error goes for all the .printAll() calls in family.cpp.
I can't see why this wouldn't work, so I hope you can.
Edit1:
Ok i changed
void printFamily()
to
void Family::printFamily()
That removes one error, but i still get
left of '.printAll' must have class/struct/union
Edit2
Ah my bad with the Person calls i changed them to
Person dad_;
and the same with the rest.
Seems like their might be an error with my Person class so i will post that also
Person.h
#include <string>
using namespace std;
class Person
{
public:
Person( const string & = "000000-0000", const string & = "N", const string & = "",const string & = "N");
~Person();
void setFirstName(const string &);
void setMiddleName(const string &);
void setLastName(const string &);
void getData(string &,string &,string &,string &);
static int getNumberOfPersons();
void printPartially() const;
void printAll() const;
bool checkForSameName(const Person &);
private:
string firstName_;
string middleName_;
string lastName_;
string socialSecNumber_;
static int numberOfPersons_;
};
Person.cpp
#include "Person.h"
#include <iostream>
int Person::numberOfPersons_ = 0;
Person::Person( const string &sNumber, const string &firstName, const string &middleName,const string &lastName )
:firstName_(firstName),middleName_(middleName),lastName_(lastName),socialSecNumber_(sNumber)
{
numberOfPersons_ ++;
}
Person::~Person()
{
numberOfPersons_--;
}
void Person::setFirstName(const string &firstName)
{ firstName_ = firstName; }
void Person::setMiddleName(const string &middleName)
{ middleName_ = middleName; }
void Person::setLastName(const string &lastName)
{lastName_ = lastName;}
void Person::getData(string &fName,string &mName,string &lName,string &sNumber)
{
fName = firstName_;
mName = middleName_;
lName = lastName_;
sNumber = socialSecNumber_;
}
int Person::getNumberOfPersons()
{
return numberOfPersons_;
}
void Person::printPartially() const
{
cout <<"Navn: "<<firstName_<<" "<<middleName_<<" "<<lastName_<<endl;
cout <<"Født: ";
for (int i = 0;i<6;i++)
{
cout <<socialSecNumber_.at(i);
}
}
void Person::printAll() const
{
cout <<"Navn: "<<firstName_<<" "<<middleName_<<" "<<lastName_<<endl;
cout <<"Personnr: "<<socialSecNumber_<<endl;
}
bool Person::checkForSameName(const Person &p)
{
if (p.firstName_ == firstName_ && p.middleName_ ==middleName_ && p.lastName_ == lastName_)
return true;
else
return false;
}
Now i am getting some new errors:
error C2011: 'Person' : 'class' type redefinition
see declaration of 'Person'
'Family::dad_' uses undefined class 'Person'
The "dad" error applies to the whole family
You have a few syntax issues.
First, you're declaring each of what are supposed to be member variables as functions which return Person. They should look like (note, no parens):
Person dad_;
Person mum_;
Person son_;
Person daughter_;
You're also missing the scoping on your definition of printFamily:
void Family::printFamily() {
...
}
Without the preceding Family::, C++ thinks you're defining a free function, and doesn't know to look inside the Family class for the declarations of dad_, mum_, etc.
Additionally, at least with the code you've shown, there's no way to initialize the people in your class. The Family constructor should take arguments to define the people, or you should have setters which allow defining them later. Right now, you'll get 4 identical people, set up however the default person constructor builds them.
I would normally prefer the constructor method, but I have other design reservations about your code to begin with (e.g. Does a family always contain mum, dad, brother, sister?) and that's not really what this question is about.
The line:
Person dad_();
says that dad_ is a function that returns a Person, not an object. Did you mean that? Similarly for others.
Try
Person dad_;
Family.h
#include "Person.h"
class Family
{
public:
Family();
void printFamily();
private:
Person dad_;
Person mum_;
Person son_;
Person daughter_;
};
Family.cpp
#include "Family.h"
Family::Family()
{
}
void Family::printFamily()
{
dad_.printAll();
mum_.printAll();
son_.printAll();
daughter_.printAll();
//printAll() is a function in the Person class that worked when
//I tested it earlier with only the person class
}
The out of line definition of a member function needs to include the class name:
void Family::printFamily()
{
//...
Surprisingly, you already got this right for the constructor but then immediately forgot...
Second, your private class members are functions, not data members (which is odd), but if that's deliberate, you need to call them:
dad_().printAll();
// ^^^

exc_bad_access error

I'm writing a program for a homework assignment. The program compiles and runs, but has a bad access error.
This is main.cpp
#include <iostream>
#include <string>
#include "Mammal.h"
#include "Dog.h"
#include "Horse.h"
#include "Pig.h"
#include "Cat.h"
using namespace std;
//Seed for ease of grading
const int SEED=100;
const int NUM_ANIMALS=5;
const int WEIGHT_LIMIT=150;
void MammalAssignment(const Mammal * new_Mammal, int choice, string newName);
void UserChoice(const Mammal * new_Mammal);
void ListAnimal(const Mammal *new_Mammal);
int main()
{
string newName, newWeight;
srand(SEED);
Mammal *new_Mammal[NUM_ANIMALS];
UserChoice(*new_Mammal);
for(int i=0; i<NUM_ANIMALS; i++)
ListAnimal(new_Mammal[i]);
//Program pauses for user input to continue
char exit_char;
cout<<"\nPress any key and <enter> to exit\n";
cin>>exit_char;
return 0;
}
void UserChoice(const Mammal * new_Mammal)
{
int choice;
bool choiceGood;
string newName;
for(int i=0;i<NUM_ANIMALS; i++){
choiceGood=false;
while(choiceGood==false)
{
cout<<"-Please choose a number 1-4 for the corresponding animal-\n"
<<"1-Dog\n2-Horse\n3-Pig\n4-Cat\n";
cin>>choice; //User choice
if(choice<=0 || choice >=5){
cout<<"Your choice is invalid\n\n";
continue;
}
choiceGood=true;
} //While loop
cout<<"\nPlease enter a name for the animal you have chosen(Ex. Fido).\n";
cin>>newName;
MammalAssignment(&new_Mammal[i], choice, newName);
} //For loop
}
void MammalAssignment(const Mammal * new_Mammal, int choice, string newName)
{
if(choice==1){
Dog newDog(rand()%(WEIGHT_LIMIT+1), newName);
new_Mammal=&newDog;
}
else if(choice==2){
Horse newHorse(rand()%(WEIGHT_LIMIT+1), newName);
new_Mammal=&newHorse;
}
else if(choice==3){
Pig newPig(rand()%(WEIGHT_LIMIT+1), newName);
new_Mammal=&newPig;
}
else if(choice==4){
Cat newCat(rand()%(WEIGHT_LIMIT+1), newName);
new_Mammal=&newCat;
}
}
void ListAnimal(const Mammal *new_Mammal)
{
cout<<"-------------------------\nName:"
<<new_Mammal->GetName()<<"\nWeight: "
<<new_Mammal->GetWeight();
}
Mammal.h
#ifndef MAMMAL_H
#define MAMMAL_H
using namespace std;
class Mammal
{
public:
Mammal(); //Default constructor
Mammal( int newWeight); //Parameterized constructor
void SetWeight(int newWeight);
virtual string GetName() const;
int GetWeight() const;
//virtual function to be defined by derived animal classes
virtual void Speak() const;
private:
int weight;
};
#endif
Mammal.cpp
#include <iostream>
#include <string>
#include "Mammal.h"
using namespace std;
Mammal::Mammal()
{
SetWeight(0);
cout<<"\nInvoking default Mammal Constructor\n";
}
Mammal::Mammal( int newWeight)
{
SetWeight(newWeight);
cout<<"\nInvoking parameterized Mammal Constructor\n";
}
void Mammal::SetWeight(int newWeight)
{
weight=newWeight;
}
int Mammal::GetWeight() const
{
return weight;
}
string Mammal::GetName() const
{}
void Mammal::Speak() const
{
cout<<"\nLadies and gentlemen, the mammal speaks...\n";
}
Dog.h
#ifndef DOG_H
#define DOG_H
#include "Mammal.h"
using namespace std;
class Dog: public Mammal
{
public:
Dog(); //Default constructor
Dog(const int& newWeight,const string& newName); //Parameterized constructor
void SetName(string newName);
string GetName() const;
//mammal virtual function
virtual void Speak() const;
private:
string name;
};
#endif
Dog.cpp
#include <iostream>
#include <string>
#include "Dog.h"
using namespace std;
//Default constructor
Dog::Dog()
{
cout<<"\nInvoking default Dog constructor\n";
}
//Parameterized constructor
Dog::Dog( const int& newWeight,const string& newName):Mammal(newWeight)
{
SetName(newName);
cout<<"\nInvoking parameterized Dog constructor.\n";
}
void Dog::SetName(string newName)
{
name=newName;
}
string Dog::GetName() const
{
return name;
}
//mammal virtual function
void Dog::Speak() const
{
Mammal::Speak();
cout<<"\nWoof!\n";
}
The other derived classes(horse, pig, and cat) are all identical to Dog. I'm getting a Exc_Bad_Access error when ListAnimals() gets to GetWeight(). As far as I can tell it's returning the right file type. Any help would be awesome
Your MammalAssignment function is returning a pointer to a local variable. Once the function returns, that memory (which was on the stack) is gone and you will crash when you access it as an object of the relevant mammal type.
You need to return a pointer to memory allocated using operator new, or possibly just an object instead of a pointer, assuming suitable copy semantics are implemented in your Mammal classes.
A revision (or initial self-education?)of memory management in C++ would be in order before you go any further. See also smart pointers, to avoid new/delete where possible and make your life easier.
Mammal *new_Mammal[NUM_ANIMALS];
You need to allocate memory using new !
Mammal *new_Mammal = new Mammal[NUM_ANIMALS];
Also I think your UserChoice function should take the pointer as a reference and not as a const value to be able to change the actual content.