简体   繁体   中英

I'm trying to learn how to properly separate class header and code

I have a class project that I did from college that "works", but isn't constructed properly.

It has a Date class and a Person class.

In my "working" code, all of the class data (constructors, members, and functions) are contained within a single header file for each class (a separate file for each class).

The program loads text file data (Persons, presidents and actors) into a vector, sorts, filters and prints the data on the console, and saves it to a file.

In the Person class constructor (and functions), the Date class is instantiated for a "birthdate" object. Then the birthday is used in the program.

The problem I'm having is this:

I can easily instantiate "Date" in the Person constructor and members, if all the class code is in a header file for each class, AND I make the Date the "Parent" class for Person. But if I don't do both of these things, then "Person" doesn't know anything about "Date" and cannot instantiate anything from Date.

If I use an #include "Date.h" in Person.h, this creates even more problems and doesn't work either.

Of course, "Date" is not a proper parent class for "Person", but it was the only way I could hack the code to make it work lol. When I first coded this years ago in college, I never did figure out how to divide the class code properly in so that it would compile and run. The "working code" with all the class code in a header file is my hack. I want to learn how to do it the right way.

I have pasted in the bare minimum example below of what "works" and what doesn't. Any tips to make this code work with the classes divided into header and .cpp files would be much appreciated.

What works:

class Date {
    private:
        int month;
        int day;
        int year;

    public:
        Date::Date() {}
        virtual ~Date() {}
        Date( int aMonth, int aDay, int aYear ) {
            this->month = aMonth;
            this->year = aYear;
            this->day = aDay;
        }

        // "Getter" functions for the Date class
        int getMonth(){return this->month;}
        int getYear() {return this->year;}
        int getDay() {return this->day;}

        // "Setter" functions for the Date class
        void setDay( int aDay ){ this->day = aDay; }
        void setMonth( int aMonth )  { this->month = aMonth; }
        void setYear( int aYear ) { this->year = aYear; }
};

class Person : public Date{
    private:
        string title;
        string firstName;
        string lastName;
        Date birthDate;

    public:
        Person::Person() {}
        Person(string title, string firstName, string lastName, Date birthDay);
        virtual ~Person() {}

        //"Getter" functions for the Person class
        string getTitle() { return title; }
        string getFirstName() { return firstName; }
        string getLastName() { return lastName; }
        Date getBirthDay() { return birthDate; }

        //"Setter" functions for the Person class
        void setTitle(string Title) { this->title = Title; }
        void setFirstName(string fName) { this->firstName = fName; }
        void setLastName (string lName) { this->lastName = lName; }
        void setBirthday (Date aBirthday) { this->birthDate = aBirthday; }
};

What doesn't work (Doesn't compile):

Date.h

class Date {
    private:
        int month;
        int day;
        int year;
    public:
        Date();
        virtual ~Date() {}
        Date( int aMonth, int aDay, int aYear );

        //Getters and setters
        int getMonth();
        int getYear() ;
        int getDay();
        void setDay( int aDay );
        void setMonth( int aMonth ) ;
        void setYear( int aYear ) ;

};

Date.cpp

#include "Date.h"
Date::Date() {}
Date::Date( int aMonth, int aDay, int aYear ) {
    this->month = aMonth;
    this->year = aYear;
    this->day = aDay;
}

int Date::getMonth(){return this->month;}
int Date::getYear() {return this->year;}
int Date::getDay()  {return this->day;}

//"Setter" functions for the Date class
void Date::setDay( int aDay ){ this->day = aDay; }
void Date::setMonth( int aMonth )  { this->month = aMonth; }
void Date::setYear( int aYear ) { this->year = aYear; }

Person.h

#include <string>

class Person{
    private:
        string title;
        string firstName;
        string lastName;
        Date birthDate;

    public:
        //Person::Person() {}
        Person(string title, string firstName, string lastName, Date birthDay); 

        //"Getter" functions for the Person class
        string getTitle() { return title; }
        string getFirstName() { return firstName; }
        string getLastName() { return lastName; }
        Date getBirthDay() { return birthDate; }

        //"Setter" functions for the Person class
        void setTitle(string Title) { this->title = Title; }
        void setFirstName(string fName) { this->firstName = fName; }
        void setLastName (string lName) { this->lastName = lName; }
        void setBirthday (Date aBirthday) { this->birthDate = aBirthday; }
    };

Person.cpp

#include "Person.h"
#include <iostream>
using namespace std;

//Person class constructor with 0 arguments
Person::Person(string atitle, string afirstName, string alastName, Date abirthDay) {
    title = atitle,
          firstName = afirstName,
          lastName = alastName,
          birthday = abirthDay)
}

//"Getter" functions for the Person class
string Person::getTitle() { return title; }
string Person::getFirstName() { return firstName; }
string Person::getLastName() { return lastName; }
Date Person::getBirthDay() { return birthDate; }

//"Setter" functions for the Person class
void Person::setTitle(string Title) { this->title = Title; }
void Person::setFirstName(string fName) { this->firstName = fName; }
void Person::setLastName (string lName) { this->lastName = lName; }
void Person::setBirthday (Date aBirthday) { this->birthDate = aBirthday; }

Operating system notes

I'm using MS Visual Studio 2012 Update 4 on a Windows 7 PC.

To prevent redefinition errors, add include guards to header files. To be portable, use:

#if !defined(THE_HEADER_NAME_H)
#define THE_HEADER_NAME_H
// Usual code and declarations here.
#endif

In Visual Studio, you can use:

#pragma once
// Usual code and declarations here.

In headers, don't write (at global scope level)

using namespace XXXXX

because that will cause all files including yours to also use namespace XXXXX which they may not want imposed upon them. If you use types that are in a namespace, type out the entire type name with namespace, so use:

std::string getTitle()

(In a cpp file, you can have 'using namespace XXXXX' after any #includes)

You have 2 problems IMHO.

First is the guards problem that Scott Langham's answer will solve.

The second is a problem of namespaces.

I assume that in your working source, you have (directly on indirectly via stdafx.h or another include) :

#include <string>

using namespace std;

It is not recommended to have using namespace std; in a .h header file ... but that means that you should use std::string instead of string :

date.h

class Date {
    private:
        int month;
        int day;
        int year;
    public:
        Date::Date() { }                                                //Date class constructor with 0 arguments
        virtual ~Date() {}                                              //Date class destructor
        Date( int aMonth, int aDay, int aYear ) {                       //Date class constructor with 3 arguments
            this->month = aMonth;                                       // Set the private member data with the argument data
            this->year = aYear;
            this->day = aDay;
            }       
        //"Getter" functions for the Date class
        int getMonth(){return this->month;}                             
        int getYear() {return this->year;}
        int getDay() {return this->day;} 

        //"Setter" functions for the Date class
        void setDay( int aDay ){ this->day = aDay; }                    
        void setMonth( int aMonth )  { this->month = aMonth; }  
        void setYear( int aYear ) { this->year = aYear; }

};

person.h (string -> std::string and remove method implementations)

#include <string>
#include "Date.h"

class Person : public Date{

private:                                                                //Private data members
    std::string title;
    std::string firstName;
    std::string lastName;
    Date birthDate;

public:
    Person::Person() {}                                                 //Person class constructor with 0 arguments
    Person(std::string title, 
        std::string firstName, 
        std::string lastName, 
        Date birthDay);                                                 //Person class constructor with 4 arguments

    virtual ~Person(){}                                                 //Person class destructor

    //"Getter" functions for the Person class
    std::string getTitle();
    std::string getFirstName();
    std::string getLastName();
    Date getBirthDay();

    //"Setter" functions for the Person class
    void setTitle(std::string Title);
    void setFirstName(std::string fName);
    void setLastName (std::string lName);
    void setBirthday (Date aBirthday);
};

person.cpp (fixed includes and constructor)

#include <string>
#include "Person.h"
#include <iostream>
using namespace std;

//Person class constructor with 0 arguments
Person::Person(string atitle, string afirstName, string alastName, Date abirthDay) {
    title = atitle,
          firstName = afirstName,
          lastName = alastName,
          birthDate = abirthDay;
}

//"Getter" functions for the Person class
string Person::getTitle() { return title; }
string Person::getFirstName() { return firstName; }
string Person::getLastName() { return lastName; }
Date Person::getBirthDay() { return birthDate; }

//"Setter" functions for the Person class
void Person::setTitle(string Title) { this->title = Title; }
void Person::setFirstName(string fName) { this->firstName = fName; }
void Person::setLastName (string lName) { this->lastName = lName; }
void Person::setBirthday (Date aBirthday) { this->birthDate = aBirthday; }

It can even be used without guards, but guard are anyway a good practice.

In fact as Date.h is included in Person.h it should really have a guard - not shown here for simplicity

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM