-2

I have wrote a simple employee test program to learn how to create and initialize class objects upon user's choice.

What I want:

  • User enters the number of employees needed
  • User enters each employee's first name, last name, date of birth, hire date

So,

Here is what I did so far:

date.h

#ifndef DATE_H
#define DATE_H

class Date
{

public:

    Date(int = 1, int = 1, int = 1990);
    ~Date();

    void setDate(int, int, int);

    void setDay(int);
    void setMonth(int);
    void setYear(int);

    int getDay() const;
    int getMonth() const;
    int getYear() const;

    int checkDay(int) const;
    int checkMonth(int) const;

    void printDate() const;

private:

    int day;
    int month;
    int year;
};

#endif

date.cpp

#include <iostream>

#include "date.h"

using namespace std;

Date::Date(int d, int m, int y)
{
    setDate(d, m, y);
}

void Date::setDate(int d, int m, int y)
{
    setDay(d);
    setMonth(m);
    setYear(y);
}

void Date::setDay(int d)
{
    day = checkDay(d);
}

void Date::setMonth(int m)
{
    month = checkMonth(m);
}

void Date::setYear(int y)
{
    year = y;
}

int Date::getDay() const
{
    return day;
}

int Date::getMonth() const
{
    return month;
}

int Date::getYear() const
{
    return year;
}

int Date::checkDay(int d) const
{
    const int daysPerMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    if (d > 0 && d <= daysPerMonth[getMonth()])
    {
        return d;
    }

    else if (getMonth() == 2 && d == 29 && (getYear() % 400 == 0 || (getYear() % 4 == 0 && getYear() % 100 != 0)))
    {
        return d;
    }

    else
    {
        cout << "Day " << d << " is invalid. Set to 1." << endl;

        d = 1;

        return d;
    }
}

int Date::checkMonth(int m) const
{
    if (m > 0 && m <= 12)
    {
        return m;
    }

    else
    {
        cout << "Month " << m << " is invalid. Set to 1." << endl;

        m = 1;

        return m;
    }
}

void Date::printDate() const
{
    cout << day << "-" << month << "-" << year << endl;
}

Date::~Date ()
{
    cout << "Date object for date class is destroyed." << endl;
}

employee.h

#ifndef EMPLOYEE_H
#define EMPLOYEE_H

#include "date.h"

class Employee
{

public:

    Employee(const char * = '\0', const char * = '\0', const Date & = birthDate, const Date & = hireDate);
    ~Employee();

    void setEmployeeData(const char *, const char *, const Date &, const Date &);

    void setFirstName(const char *);
    void setLastName(const char *);

    void setBirthDateObject(Date);
    void setHireDateObject(Date);

    const char *getFirstName();
    const char *getLastName();

    Date getBirthDateObject() const;
    Date getHireDateObject() const;

    void printDate() const;

private:

    char first_name[25];
    char last_name[25];

    static Date birthDate;
    static Date hireDate;
};

#endif

employee.cpp

#include <iostream>

#include "employee.h"

using namespace std;

Employee::Employee(const char *first, const char *last, const Date &dateOfBirth, const Date &dateOfHire)
{
    setEmployeeData(first, last, dateOfBirth, dateOfHire);  
}

void Employee::setEmployeeData(const char *first, const char *last, const Date &dateOfBirth, const Date &dateOfHire)
{
    setFirstName(first);
    setLastName(last);

    setBirthDateObject(dateOfBirth);
    setHireDateObject(dateOfHire);
}


void Employee::setFirstName(const char *first)
{
    int length = strlen(first);

    if (length < 25)
    {
        length = length;
    }

    else
    {
        length = 24;
    }

    strncpy(first_name, first, length);

    first_name[length] = '\0';
}

void Employee::setLastName(const char *last)
{
    int length = strlen(last);

    if (length < 25)
    {
        length = length;
    }

    else
    {
        length = 24;
    }

    strncpy(last_name, last, length);

    last_name[length] = '\0';
}

void Employee::setBirthDateObject(Date dateOfBirth)
{
    birthDate = dateOfBirth;
}

void Employee::setHireDateObject(Date dateOfHire)
{
    hireDate = dateOfHire;
}

const char *Employee::getFirstName()
{
    return first_name;
}

const char *Employee::getLastName()
{
    return last_name;
}

Date Employee::getBirthDateObject() const
{
    return birthDate;
}

Date Employee::getHireDateObject() const
{
    return hireDate;
}

void Employee::printDate() const
{
    cout << first_name << ' ' << last_name << endl;

    cout << "Hired date: "; hireDate.printDate(); cout << endl;

    cout << "Birth date: "; birthDate.printDate(); cout << endl;
}

Employee::~Employee()
{
    cout << "Employee object for employee class destroyed." << endl;
}

main.cpp

#include <iostream>
#include <vector>

#include "employee.h"

using namespace std;

int main()
{
    const int number = 10;

    char fname[25];
    char lname[25];

    int bd, bm, by, hd, hm, hy;

    vector<Date> emp_db(number);
    vector<Date> emp_hd(number);
    vector<Employee> emp(number);

    for (int i = 0; i < number; i++)
    {
        cout << "Employee " << i + 1 << endl;

        cout << "Enter first name: ";
        cin >> fname;

        cout << "Enter last name: ";
        cin >> lname;

        cout << "Enter date of birth: ";
        cin >> bd >> bm >> by;

        cout << "Enter hire date: ";
        cin >> hd >> hm >> hy;

        emp_db[i].setDate(bd, bm, by);
        emp_hd[i].setDate(hd, hm, hy);
        emp[i].setEmployeeData(fname, lname, emp_db[i], emp_hd[i]);
    }

    return 0;
}

Everything is compiling fine but is giving linker error when built:

employee.obj : error LNK2001: unresolved external symbol "private: static class Date Employee::birthDate" (?birthDate@Employee@@0VDate@@A) main.obj : error LNK2001: unresolved external symbol "private: static class Date Employee::birthDate" (?birthDate@Employee@@0VDate@@A) employee.obj : error LNK2001: unresolved external symbol "private: static class Date Employee::hireDate" (?hireDate@Employee@@0VDate@@A) main.obj : error LNK2001: unresolved external symbol "private: static class Date Employee::hireDate" (?hireDate@Employee@@0VDate@@A) Debug/lab 4a.exe : fatal error LNK1120: 2 unresolved externals

I'm a beginner in this business so please stay low and tell me that is it right what I'm doing in main()?

Update: I have a doubt that something in main() is causing it. Look at my main() and tell me is it right? I mean, does C++ allow what I'm doing?

Silver Falcon
  • 176
  • 1
  • 1
  • 11
  • possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](http://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – πάντα ῥεῖ May 25 '14 at 10:13
  • The error notwithstanding, you have a design problem: in your current code all your employees share the same age and hiring date. You will have to fix this. – Frédéric Hamidi May 25 '14 at 10:16
  • @FrédéricHamidi How? Birth date and hiring date are taken from user every time the `for` runs.. – Silver Falcon May 25 '14 at 10:19
  • @SilverFalcon, these are *static* members, they are shared between all the instances of your class. Assigning them in a loop only overwrites their values again and again, but in the end all instances will have the same values in these members. You want non-static, instance members instead. – Frédéric Hamidi May 25 '14 at 10:21
  • @FrédéricHamidi But when I remove the `static`, it says: `error C2648: 'birthDate' : use of member as default parameter requires static member` in `employee.cpp` – Silver Falcon May 25 '14 at 10:23
  • @SilverFalcon, that's because your constructor uses them as default argument values (`const Date & = birthDate, const Date & = hireDate`). For unnamed arguments. That it does not use. I honestly don't understand what you want to achieve with this, maybe you should review your whole design. – Frédéric Hamidi May 25 '14 at 10:25
  • @FrédéricHamidi Yes it sucks! I know. So please hear and answer this: In past two minutes I have learned that **if you want to take number of objects and put individual data in them from user, then there is no need for constructor (or it should be empty) if you are using separate functions like `setEmployeeData()` etc** Please reply am I right? – Silver Falcon May 25 '14 at 10:34
  • @SilverFalcon, nope, that's not mutually exclusive. You can have setter methods like `setEmployeeData()` that set instance members *and* a non-default constructor that initializes them to default values (or to specific values passed as arguments). It looks like you're confused about basic aspects of OO programming, I would suggest a good book :) – Frédéric Hamidi May 25 '14 at 10:37
  • @FrédéricHamidi Yes, till this day I was using constructors to initialize members. But in this specific case I think that the constructor should be empty. What do you think? – Silver Falcon May 25 '14 at 10:44

1 Answers1

2

add to Employee.cpp the static members initialize statements

Date Employee::birthDate;
Date Employee::hireDate;
NirMH
  • 4,769
  • 3
  • 44
  • 69
  • Where do I add these in `Employee.cpp`? In constructor definition? – Silver Falcon May 25 '14 at 10:20
  • 1
    Your answer is technically right, but I believe these members should not be static in the first place. – Frédéric Hamidi May 25 '14 at 10:22
  • @SilverFalcon: in the cpp file - in the global scope. as these members are static, you'll need to tell the compiler how to create the memory (object) for them.. as they are static - they can't be defined in the C-tor of the class object – NirMH May 25 '14 at 10:23
  • @FrédéricHamidi: i am answering the specific question of the submitter, not judging his/her design... he/she will need to deal with the problem themselves... – NirMH May 25 '14 at 10:24
  • @NirMH Thanks that worked. But the program crashes because of **design problems** as mentioned by Frederic Hamidi. :( – Silver Falcon May 25 '14 at 10:36
  • :) - now you've learned an excellent lesson :)... go ahead and fix the design problem you had.... (and kindly approve my answer if i may) – NirMH May 25 '14 at 10:38