Thread: Composite inheritance

  1. #1
    Registered User
    Join Date
    Aug 2001
    Posts
    6

    Composite inheritance

    Hello,
    Thank you for reading this and for any help in advance. I checked the FAQs and tutorials but this type of question did not seem to arise, and apologize if its just a simple, uninteresting problem.

    I'm attempting to do the following:
    1. Have one class of "Employee" serving as a base class, with differing types of employees as derived classes (such as "hourly worker", "commission worker" etc.) and polymorphically calculate the pay for each.
    2. Within the private/protected members of the Employee base class is another class, "Date", which just holds a particular date for each employee.
    3. The problem: how to send user-inputted data to both classes utilizing the parameters of each of the differing functions? I've been trying to do it in main () with the following code (hopeless I realize):

    case 1: pEmployee [i] = new Employee (fname, lname, salaryType, baseSalary, birthMonth, birthDay, birthYear);

    //pEmployee [i] = new Boss (fname, lname, salaryType, baseSalary), (birthMonth, birthDay, birthYear);
    break;
    //I'd rather use the commented out "new Boss" code somehow...

    ...but I have no idea how to have the pointer to the employee object array take not only the "Date" class data as well as its own data, but then take in or copy the derived class ("Boss") data as well so the polymorphic activity for calculating the pay of each derived class can take place. Should I overload the assignment operator and just force the Boss derived-class to take the Employee base-class info? Am I just way off (probably)?

    Here is the entire program code that I have to now...it is of course incomplete. The code in question is in the main () function near the end in the switch () area.

    Thank you again for any help. I hope this makes some sense, and sorry for the length...

    #include <iostream>
    using namespace std;

    #include <iomanip>
    #include <cassert>

    //#define birthdayRaise 100.00
    #define NAMELENGTH 100
    #define DEPARTMENTS 10

    class Date //pretty much straight out of the Deitel C++ book
    {
    public:
    Date (int birthMonth = 1, int birthDay = 2, int birthYear = 1900); //default constructor.
    void Print () const; //print data in mo/day/year format.
    ~Date (); //provided to confirm destruction order.
    private:
    int month; //1-12.
    int day; //1-31 based on month.
    int year; //any year.

    int CheckDay (int birthDay); //utility function to test proper day for month and year.
    int CheckMonth (int birthMonth);
    int CheckYear (int birthYear);
    };

    /* Date constructor: confirm proper value for month, call utility function
    CheckDay () to confirm the proper value for day variable. */
    Date:ate (int birthMonth, int birthDay, int birthYear)
    {
    month = CheckMonth (birthMonth); //validate month
    day = CheckDay (birthDay); //validate day
    year = CheckYear (birthYear);

    } //end Date constructor

    //validate month
    int Date::CheckMonth (int birthMonth)
    {
    if (birthMonth > 0 && birthMonth <= 12) //month validation
    {
    month = birthMonth;
    }
    else
    {
    month = 1;
    cout << "Month " << birthMonth << " is invalid. Set to month 1.\n";
    }
    return month;
    }

    /* Utility function to confirm proper day value based on month and year.
    Is the year 2000 a leap year? */
    int Date::CheckDay (int dyTest)
    {
    static const int daysPerMonth [13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    if (dyTest > 0 && dyTest <= daysPerMonth [month])
    {
    return dyTest;
    }

    if (month == 2 && dyTest == 29 && (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0 )))
    {
    return dyTest;
    }

    cout << "Day " << dyTest << " is invalid. Setting to day 1.\n";

    return 1; //ostensibly leaves object in a consistent state if a bad value exists.
    }

    //validate year
    int Date::CheckYear (int yr)
    {
    if (yr >= 1900 && yr <= 2100)
    {
    year = yr;
    }
    else
    {
    year = 0000;
    cout << "Year " << yr << " is not valid. Just set to 0000.\n";
    }
    return year;
    }

    /* Print the Date object in form month/day/year */
    void Date::Print () const
    {
    cout << month << '/' << day << '/' << year;
    }//end Date::Print ()

    /* Destructor: provided to confirm destruction order */
    Date::~Date ()
    {
    //cout << "Date object destructor for date: ";
    //Print ();
    //cout << endl;
    }
    //end Date class




    class Employee //also mostly out of the Deitel book
    {
    public:
    //Employee () : firstname (NULL), lastname (NULL), departmentCode (0) {}
    Employee (char *first, char *last, int deptCd = 0, int = 0, int = 0, int = 0);
    ~Employee ();
    char SetFirstName (const char *first); //return first name
    char SetLastName (const char *last); //return last name
    int SetEmployeeCode (int deptCd);

    const char *GetFirstName () const;
    const char *GetLastName () const;
    const int GetEmployeeCode () const;

    virtual double Earnings () const;
    virtual void Print () const;
    protected:
    char *firstname;
    char *lastname;
    int departmentCode;
    Date birthDate;
    };

    //constructor dynamically allocates space for first/last name, strcpy to copy into object.
    Employee::Employee (char *first, char *last, int deptCd,
    int birthMonth, int birthDay, int birthYear)
    : birthDate (birthMonth, birthDay, birthYear)
    {
    Employee::SetFirstName (first);
    Employee::SetLastName (last);

    departmentCode = deptCd;
    }

    //return first name of employee
    char Employee::SetFirstName (const char *first)
    {
    firstname = new char [strlen (first) + 1];
    assert (firstname != 0);
    strcpy (firstname, first);

    return *firstname;
    }

    //return last name
    char Employee::SetLastName (const char *last)
    {
    lastname = new char [strlen (last) + 1];
    assert (lastname != 0);
    strcpy (lastname, last);

    return *lastname;
    }
    //check for valid dept. code
    int Employee::SetEmployeeCode (int deptCd)
    {
    if (deptCd <= 0 && deptCd > DEPARTMENTS)
    {
    cout << "There was an invalid department code entered.\n"
    << "Setting the code to 1.";
    departmentCode = 1;
    }
    else
    {
    departmentCode = deptCd;
    }
    return departmentCode;
    }

    //destructor deallocates dynamically allocated memory
    Employee::~Employee ()
    {
    delete [] firstname;
    delete [] lastname;
    }

    //return pointer to firstname, const return type prevents caller from modifying private
    //data. Caller should copy returned string before destructor deletes dynamic storage to
    //prevent undefined pointer.
    const char *Employee::GetFirstName () const
    {
    return firstname;
    }

    //same as GetFirstName () above
    const char *Employee::GetLastName () const
    {
    return lastname;
    }

    const int Employee::GetEmployeeCode () const
    {
    return departmentCode;
    }

    double Employee::Earnings () const
    {
    return;
    }

    //print
    void Employee::Print () const
    {
    cout << firstname << ' ' << lastname << endl;
    }
    //end Employee class



    class Boss : public Employee //inherits Employee class
    {
    public:
    Boss (const char *first, const char *last, int deptCd, double sal);

    void SetWeeklySalary (double sal);

    virtual double Earnings () const;
    virtual void Print () const;
    private:
    double weeklySalary;
    };

    Boss::Boss (const char *first, const char *last, int deptCd, double sal)
    : Employee (first, last, deptCd)
    {
    SetWeeklySalary (sal);
    }

    void Boss::SetWeeklySalary (double sal)
    {
    weeklySalary = sal > 0 ? sal : 0;
    }

    double Boss::Earnings () const
    {
    return weeklySalary;
    }

    void Boss::Print () const
    {
    cout << "Boss: ";
    Employee::Print ();
    }
    //end Boss class


    class CommissionWorker : public Employee
    {
    public:
    CommissionWorker (const char *first, const char *last, int deptCd,
    double sal = 0.0, double comm = 0.0, int quant = 0);
    void SetSalary (double sal);
    void SetCommission (double comm);
    void SetQuantity (int quant);

    virtual double Earnings () const;
    virtual void Print () const;
    private:
    double salary; //base salary per week
    double commission; //amount per item sold
    int quantity; //total items sold for the week
    };

    CommissionWorker::CommissionWorker (const char *first, const char *last, int deptCd,
    double sal, double comm, int quant) : Employee (first, last, deptCd)
    {
    SetSalary (sal);
    SetCommission (comm);
    SetQuantity (quant);
    }

    void CommissionWorker::SetSalary (double sal)
    {
    salary = sal > 0 ? sal : 0;
    }

    void CommissionWorker::SetCommission (double comm)
    {
    commission = comm > 0 ? comm : 0;
    }

    void CommissionWorker::SetQuantity (int quant)
    {
    quantity = quant > 0 ? quant : 0;
    }

    double CommissionWorker::Earnings () const
    {
    return salary + commission * quantity;
    }

    void CommissionWorker::Print () const
    {
    cout << "\nCommission Worker: ";
    Employee::Print ();
    }
    //end CommissionWorker class


    class PieceWorker : public Employee
    {
    public:
    PieceWorker (const char *first, const char *last, int deptCd, double wa = 0.0, int quant = 0);
    void SetWage (double wa);
    void SetQuantity (int quant);

    virtual double Earnings () const;
    virtual void Print () const;
    private:
    double wagePerPiece; //wage for each piece output
    int quantity; //output per week
    };

    PieceWorker::PieceWorker (const char *first, const char *last, int deptCd, double wa, int quant)
    : Employee (first, last, deptCd)
    {
    SetWage (wa);
    SetQuantity (quant);
    }

    //set the wage
    void PieceWorker::SetWage (double wa)
    {
    wagePerPiece = wa > 0 ? wa : 0;
    }

    //set the number of items output
    void PieceWorker::SetQuantity (int quant)
    {
    quantity = quant > 0 ? quant : 0;
    }

    //determine the pieceworkers earnings
    double PieceWorker::Earnings () const
    {
    return quantity * wagePerPiece;
    }

    //print the pieceworker's name
    void PieceWorker::Print () const
    {
    cout << "\nPiece Worker: ";
    Employee::Print ();
    }
    //end PieceWorker class


    class HourlyWorker : public Employee
    {
    public:
    HourlyWorker (const char *first, const char *last, int deptCd, double wa = 0.0, double hrs = 0.0);
    void SetWage (double wa);
    void SetHours (double hrs);

    virtual double Earnings () const;
    virtual void Print () const;
    private:
    double wage;
    double hours;
    };

    HourlyWorker::HourlyWorker (const char *first, const char *last, int deptCd,
    double wa, double hrs) : Employee (first, last, deptCd)
    {
    SetWage (wa);
    SetHours (hrs);
    }

    //set wage
    void HourlyWorker::SetWage (double wa)
    {
    wage = wa > 0 ? wa : 0;
    }

    //set hours worked
    void HourlyWorker::SetHours (double hrs)
    {
    hours = hrs >= 0 && hrs < 168 ? hrs : 0;
    }

    //get the HourlyWorker's pay
    double HourlyWorker::Earnings () const
    {
    if (hours <= 40) //no ot
    return wage * hours;
    else //ot paid at wages * 1.5
    return 40 * wage + (hours - 40) * wage * 1.5;

    }

    //print the HourlyWorker's name
    void HourlyWorker::Print () const
    {
    cout << "\n Hourly Worker: ";
    Employee::Print ();
    }

    void VirtualViaPointer (const Employee *baseClassPtr);
    void VirtualViaReference (const Employee &baseClassRef);

    int main (void)
    {
    /* Local variables */
    Employee *pEmployee [3];
    //Date birthDate;

    char *fname = NULL;
    char *lname = NULL;
    double baseSalary = 0.0;
    int salaryType = 0;
    int pieceOutput = 0;
    int hoursWorked = 0;
    double commisRate = 0.0;
    int quantitySold = 0;

    int birthMonth = 0;
    int birthDay = 0;
    int birthYear = 0;

    /* Statements */
    cout << setiosflags (ios::fixed | ios::showpoint)
    << setprecision (2);

    cout << "**A short program to give a raise on an employee's birthday.**\n\n"
    << " --------------------------------------------------------- \n" <<endl;
    cout << "When prompted, you will have the following options for the type "
    << "of employee salary: \n"
    << "1. Management. \n"
    << "2. Commission Worker.\n"
    << "3. Piece worker.\n"
    << "4. Hourly worker.\n\n" << endl;

    for (int i = 0; i < 3; i++)
    {
    fname = new char [NAMELENGTH];
    lname = new char [NAMELENGTH];

    cout << "\n";
    cout << "The first name of the employee is: ";
    cin.getline (fname, 10, '\n');

    cout << "The last name: ";
    cin.getline (lname, 10, '\n');

    cout << "Please enter the birthdate of the employee: \n"
    << "\nMonth: ";
    cin >> birthMonth;
    cin.get ();

    cout << "\nBirth Day: ";
    cin >> birthDay;
    cin.get ();

    cout << "\nYear: ";
    cin >> birthYear;
    cin.get ();

    cout << "Enter the employee's base salary: ";
    cin >> baseSalary;
    cin.get ();

    cout << "Please enter the employee salary type (seen above); ";
    cin >> salaryType;
    cin.get (); //eliminates newline char from input buffer

    //Date (birthMonth, birthDay, birthYear);

    switch (salaryType)
    {
    case 0: cout << "Invalid employee salary type entered. Please try again.";
    break;
    case 1: pEmployee [i] = new Employee (fname, lname, salaryType, baseSalary, birthMonth, birthDay, birthYear);
    //pEmployee [i] = new Boss (fname, lname, salaryType, baseSalary), (birthMonth, birthDay, birthYear);
    break;
    case 2: cout << "Please enter the commission amount: ";
    cin >> commisRate;
    cin.get ();

    cout << "Enter the amount of items sold: ";
    cin >> quantitySold;
    cin.get ();

    pEmployee [i] = new CommissionWorker (fname, lname, salaryType, baseSalary, commisRate, quantitySold);
    break;
    case 3: cout << "For the piece worker, please enter the amount of completed pieces: ";
    cin >> pieceOutput;
    cin.get ();

    pEmployee [i] = new PieceWorker (fname, lname, salaryType, baseSalary, pieceOutput); //wage
    break;
    case 4: cout << "For hourly employees, please enter the amount of hours worked: ";
    cin >> hoursWorked;
    cin.get ();

    pEmployee [i] = new HourlyWorker (fname, lname, salaryType, baseSalary, hoursWorked); //wage
    break;
    default: cout << "Invalid employee salary type entered. Please try again.";
    }
    }
    return 0;
    }

  2. #2
    Unregistered
    Guest
    I don't know that you can access data in derived class not also part of base class by using pointer to base.

    #include <iostream.h>

    class base
    {
    public :
    void setAge(int input) {age = input;}
    int getAge() {return age;}
    private:
    int age;
    };

    class derived : public base
    {
    public:
    void setGender(char ch) {gender = ch;}
    char getGender() {return gender;}
    private:
    char gender;
    };

    int main()
    {
    base * sample[2];

    base first;
    sample[0] = &first;

    derived second;
    sample[1] = &second;

    sample[0]->setAge(24);
    cout << sample[0]->getAge() << endl;

    sample[1]->setAge(30);
    cout << sample[1]->getAge() <<endl;


    char ch = 'F';
    //sample[1]->setGender(ch); ??????
    //cout << sample[1]->getGender() <<endl;
    return 0;
    }

    Will have to compile when I have compiler available.

  3. #3
    Registered User
    Join Date
    Aug 2001
    Posts
    6
    Unregistered...

    Thank you very much for your reply. The professionalism of this board is such a breath of fresh air.

    I think I see what you are doing...rather than having boat-loads of parameters (as I'm more used to when writing things in C) it would appear to be better to use the "Get" and "Set" functions as you indicate, then build the object from that. Or at least I think that would be the idea...

    What was flummoxing me the most was when attempting to initialize a derived object from user-inputted data (the "Boss" derived class) from a pointer to the base class (pEmployee), the compiler (Code Warrior) would immediately jump to the Date class, which is a composite member of the Employee base class. How to get that data by parameter, which is then to fit into the smaller derived class parameter list was the problem.

    It would be better for me to re-think things a bit...

    Thank you,

    inakappeh

  4. #4
    Unregistered
    Guest
    initializing the members of a object buried in another object should be possible along these lines:

    class Date
    {
    public:
    int month;
    int day;
    int year;
    };

    class Employee
    {
    public:
    int age;
    Date hireDate;
    };

    int main()
    {
    Employee first;
    first.age = 23;
    first.hireDate.month = 7;
    first.hireDate.day = 18;
    first.hireDate.year = 2000;

    cout << "the employee is of age " << first.age << " and was
    hired on " << first.hireDate.month << "-" << first.hireDate.day
    << "-" << first.hireDate.year << endl;

    return 0;
    }

    Or the equivalent using pointers or array notation as needed. However, I an concerned the problem is based in whether you can access data in a derived class using a pointer to base class if the data in the derived class is not part of the base class. I have only used base class pointers to advantage when calling functions present in base class that are overridden in derived classes.

  5. #5
    Registered User
    Join Date
    Aug 2001
    Posts
    6
    Actually yes this is a part of the problem I think. Utilizing a base-class pointer, I need to access/manipulate data not found in the base class. And another thing that is confusing is whether or not the Date class data in the Employee base class is accessible in the derived classes, and if so, how to access them. I plan to spend a few hours tonight to fiddle with it. Technically it would seem that protected data members of the base class are accessible below...

    I suppose more time spent hacking at it would be more beneficial than wasting board space ruminating....

    Thanks for your help...I did understand your code fragments also...

    Best regards
    inakappeh

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 16
    Last Post: 06-08-2009, 03:03 PM
  2. Multiple Inheritance - Size of Classes?
    By Zeusbwr in forum C++ Programming
    Replies: 10
    Last Post: 11-26-2004, 09:04 AM
  3. inheritance and performance
    By kuhnmi in forum C++ Programming
    Replies: 5
    Last Post: 08-04-2004, 12:46 PM
  4. Inheritance vs Composition
    By Panopticon in forum C++ Programming
    Replies: 11
    Last Post: 01-20-2003, 04:41 AM
  5. Homework help
    By Jigsaw in forum C++ Programming
    Replies: 2
    Last Post: 03-06-2002, 05:56 PM