Avatar of GPicasso
GPicasso
 asked on

Confused with C++ header files

Ok I've got a c++ project that I want to break down into properly organized header files but the help has me confused
Here is an example i found on the internet:


Date.h:
	
#ifndef DATE_H
#define DATE_H
 
class Date
{
private:
    int m_nMonth;
    int m_nDay;
    int m_nYear;
 
    Date() { } // private default constructor
 
public:
    Date(int nMonth, int nDay, int nYear);
 
    void SetDate(int nMonth, int nDay, int nYear);
 
    int GetMonth() { return m_nMonth; }
    int GetDay()  { return m_nDay; }
    int GetYear() { return m_nYear; }
};
 
#endif

Open in new window

Date.cpp:
	
#include "Date.h"
 
// Date constructor
Date::Date(int nMonth, int nDay, int nYear)
{
    SetDate(nMonth, nDay, nYear);
}
 
// Date member function
void Date::SetDate(int nMonth, int nDay, int nYear)
{
    m_nMonth = nMonth;
    m_nDay = nDay;
    m_nYear = nYear;
}

Open in new window


Ok my issue here is that there is actual code in the header file! but only for the accessors ...  not for the constructor.  Seems inconsistent to me so I'm not sure how I should be fixing my own code (Which will not compile as is due to lack of forward declaration.)
C++Programming Theory

Avatar of undefined
Last Comment
jkr

8/22/2022 - Mon
jkr

Can you post your code? That'd be much easier and more efficient ;o)
GPicasso

ASKER
#include <stack>
#include <vector>
#include <string>
#include <queue>
#include <iostream>

using namespace std;

#define NUMBER_OF_PROCESSORS 8
#define MAX_JOBS 2


class Processor
/* This class represents processors                 *
 * it includes a processor ID but it's not          *
 * yet important                                    *
 *                                                 */
{
private:
    int processorID_;        // This is a unique integet to tell one processor 
                             // from the next
    string type_;  //This tells what type of processor 
                                          // is attached to the object
public:
    Processor()
    {
        processorID_ = 0;
        type_ =  "GenuineMakeBelieve";
        // this is all just examples we could put all kinds of stuff
        // in here to tie this to a real processor and get statistics 
        // or even have affinity for some jobs to certian types of processors
        // but this is all make believe anyhow
    }
    int getID()
    /* This should return the processor ID*/
    {
        return processorID_;
    }
    string getType()
    /*This should return a string identifying the sort of processor
     */
    {
        return type_;
    }
    
};
class System
/* This class represents the system it's for storing the state of anything
 * that doesn't clearly belong in some other class
 * right now it only stores the free processor pool and the current next 
 * process ID
 */
{
private:

    int nextPid;
    vector<Processor> freePool_;
public:
    System()
    {   
        freePool_ = new vector<Processor>;
        nextPid = 0;
        
    }
    int getPID()   /// static int getPID() ???
    /*This allocates and returns the next available process ID*/
    {
        return ++nextPid; 
    }
    Processor getProcessor()
    /* This method gets a free processor from the system*/
    {
        Processor r = freePool_.back();
        freePool_.pop_back();
        return r;
    }
    void takeProcessor(Processor processor)
    /* This method gives the processor back to the system*/
    {
        freePool_.push_back(processor);
    }
   
};


class Job
/* The job class represents an actual job with a name
 * a stack of captured processors a list of ticks and a PID for the job*/
{
private:
    vector<Processor> captiveProcessors_;
    string name_;
    int PID_;
    int ticksRemaining_;
public:
    Job(string name, int processors, int ticks)
    {
        name_ = name;
        ticksRemaining_ = ticks;
        PID_ = system_.getPID();
    }
    void takeProcessor(Processor processor)
    /*This takes a processor and makes it captive*/
    {
        captiveProcessors_.push_back(processor);
    }
    void tick()
    /*decrement the ticks and return ticks remaining*/
    {
        return --ticksRemaining_;
    }
    
    
    bool operator>= (Job &job1, Job &job2)
    {
        return job1.ticksRemaining_ >= job2.ticksRemaining_;
    }
    bool operator<= (Job &job1, Job &job2)
    {
        return job1.ticksRemaining_ <= job2.ticksRemaining_;
    }
    bool operator== (Job &job1, Job &job2)
    {
        return job1.ticksRemaining_ == job2.ticksRemaining_;
    }
    bool operator!= (Job &job1, Job &job2)
    {
        return job1.ticksRemaining_ != job2.ticksRemaining_;
    }
    friend ostream &operator<<(ostream& out,const Job& job)
    {
        out <<job.name_ + "\t" job.PID_ + + "\t" + job.ticksRemaining_ + "\t\n";
        return out;
    }
};

class Scheduler
/* This class represents a scheduler object
 What should happen here is the user should be able to submit
 * a job request (sendjobrequest). it should get enqueud in a regular queue and
 *  at each tick it will 
 * convert those requests into 
 */
{ 
private:
    vector<Job> runQueue_;  //  This is the queue that running jobs sit in
    vector<Job> waitQueue_; //  This is the queue that not running jobs sit in
    void tickRunQueue()
    /*private method to manipulate the runQueue*/
    {
        for (int i=0; i<=runQueue_.size();i++)
        {
           if (0 >= runQueue_.at(i).tick())
           /* if there are no ticks left anyhow then free the memory and remove 
            the pointer from the Queue*/
           {
               delete(runQueue_.back());
               runQueue_.pop_back();
           }
           
           cout << runQueue_.at(i);
        }
    }
    void tickWaitQueue()
    /* private method to move a */
    {
        runQueue_.push_back(waitQueue_.back());
        waitQueue_.pop_back();
    }
   
public:
    Scheduler()
    {
        runQueue_ = new vector<Job>();
        waitQueue_ = new vector<Job>();
    }
    processJobRequest(JobRequest jobRequest)
    /* This converts a job request into an actual job
       This is where jobRequests go to die*/
    {
        waitQueue_.push_back(new Job(jobRequest.getName(), jobRequest.getProcessingRequirements(),jobRequest.getTicksRequired()));
        delete(jobRequest);
    }
    tick()
    {
        // I would make a queue that you can put new submissions to and a threaded
        // shell.. but I looked at pthreads,, no that's not going to happen, and 
        // honestly I don't know any other sensible way to allow users to submit
        // a job during any tick.. but here are some comments
        // if (submissionqueue) {pop the thing off the queue and processoJobRequest()
        // good enough  
        // I take that back maybe I'll use kbhit() to get some text input if I have time
        // forget it I don't even have the curses libraries installed.. no interactive shell
    
        // if queue is not empty and enough processors are available then pop
        // a job off and give it processors     
        
    }
    
};






class JobRequest
/*  This represents a request to create a job it had yet to actually
 * move on to that point in it's lifecycle.. note the lack of PID
*/
{
private:
    string name_;
    int numberOfProcessors_;
    int numberOfTicks_;
public:
    JobRequest(string name, int numberOfProcessors, int numberOfTicks)
    {
       name_ = name_;
       numberOfProcessors_ = numberOfProcessors;
       numberOfTicks_ = numberOfTicks;
    }
    string getName()
    /*returns the name of the job, exmple: ls, pwd, javac*/
    {
        return name_;
    }
    int getProcessingRequirements()
    /*returns the number of processors required to run this job*/
    {
        return numberOfProcessors_;
    }
    int getTicksRequired()
    /* Returns the number of ticks this program is going to consume*/
    {
        return numberOfTicks_;
    }
};

System system_; // this simulates system features normally outside of the scheduler

int main()
{
    // System objects, scheduler and system get created here
    // Processors get created too
 
    system_ = new System();
    Scheduler scheduler = new Scheduler();
    
    /*make the processors*/
    for (int i = 0; i < NUMBER_OF_PROCESSORS; i++)
    {
        system_.takeProcessor(new Processor());
    }
    
    scheduler.processJobRequest(new JobRequest("nethack", 2, 4));
    scheduler.processJobRequest(new JobRequest("gcc", 4, 2));
    scheduler.processJobRequest(new JobRequest("pwd", 7, 3));
    scheduler.processJobRequest(new JobRequest("javac", 3, 8));
    scheduler.processJobRequest(new JobRequest("clear", 3, 3));
    scheduler.processJobRequest(new JobRequest("fortune", 1, 1));
            
    
    scheduler.processJobRequest(new JobRequest("nethack", 2, 4));
    scheduler.processJobRequest(new JobRequest("gcc", 4, 2));
    scheduler.processJobRequest(new JobRequest("pwd", 7, 3));
    scheduler.processJobRequest(new JobRequest("javac", 3, 8));
    scheduler.processJobRequest(new JobRequest("clear", 3, 3));
    scheduler.processJobRequest(new JobRequest("fortune", 1, 1));
            
    
    scheduler.processJobRequest(new JobRequest("nethack", 2, 4));
    scheduler.processJobRequest(new JobRequest("gcc", 4, 2));
    scheduler.processJobRequest(new JobRequest("pwd", 7, 3));
    scheduler.processJobRequest(new JobRequest("javac", 3, 8));
    scheduler.processJobRequest(new JobRequest("clear", 3, 3));
    scheduler.processJobRequest(new JobRequest("fortune", 1, 1));
            
    
    scheduler.processJobRequest(new JobRequest("nethack", 2, 4));
    scheduler.processJobRequest(new JobRequest("gcc", 4, 2));
    scheduler.processJobRequest(new JobRequest("pwd", 7, 3));
    scheduler.processJobRequest(new JobRequest("javac", 3, 8));
    scheduler.processJobRequest(new JobRequest("clear", 3, 3));
    scheduler.processJobRequest(new JobRequest("fortune", 1, 1));
    
    while(1)
    {
        scheduler.tick();
    }
            
    
}

Open in new window


As you can see I junked it up quite a bit moving things around and then realized putting all this into a properly structured c++ project with headers for all the classes would fix a lot of my issues which seemed to be forward declaration related.

But the code is here enough that I think a good C++ programmer could visualize the way it should be.

There are other problems I'm sure and maybe even some missing code but I can't take this any further until I've done some re-organizing.
ASKER CERTIFIED SOLUTION
jkr

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
pepr

>> Ok my issue here is that there is actual code in the header file! but only for the accessors ...  not for the constructor.

Notice the line 15 in your header
Date(int nMonth, int nDay, int nYear);

Open in new window


This is the constructor.  Only the default constructor is made private to prevent the situation when anyone tries to create "uninitialized" object in the sense of its functionality.  In other words, the date object must be given some date when created.  It cannot be postponed.  The implementation of the constructor (its body) is located at the .cpp file.  The compiler actually compiles the .cpp files.  The .h files are included as text by the #include directive.  The result is the same as if you copied it to that place.

The accessor GetMonth() etc should actually be made inlines to make the code possibly more efficient.
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
jkr

pepr, try to compile his original code - that was not an issue.