Weird programming c++ error

Thread Starter

mentaaal

Joined Oct 17, 2005
451
Hey guys, I am having a problem with a very simple inheritance program. I have made a base and derived class for a simple assignment. The strange thing is I cannot get the program to compile without including a cout which references one of the used functions in the application file into the base class' constructor. If i ommit this cout statement, the compiler returns the error:
test file.obj : error LNK2019: unresolved external symbol "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const & __thiscall employee::getpaytype(void)const " (?getpaytype@employee@@QBEABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) referenced in function _main
I tried to rewrite a simple program with the same idea but could not replicate the error. The problem area is highlighted in the definition file below.
Header file containing base class and derived class prototypes
Rich (BB code):
#include <string>
#include <iostream>
using namespace std;

class employee
{
public:
    employee(int eid, const char * name, float p,const char * ptype);
    inline const string & getname() const; 
    inline float getpayrate() const;
    inline const string & getpaytype() const;
    float get_pay();
    
protected:
    virtual void pay() =0;//pure virtual function ensures that employee is an Abstract base class    
    int employee_id;
    string employee_name;
    float payrate;
    float tot_pay;
    string paytype;
};




class manager : public employee
{
public:
    manager(int Eid, const char *, float P, const char * P_type, int Supers);    
    inline int getsupervisors() const;
    inline void set_supers(int);
    virtual void pay();

private:
    int supervisors;

};
Definition file:
Rich (BB code):
#include "headers.h"

employee::employee(int eid, const char* name, float p, const char * ptype)
{
    employee_id = eid;
    employee_name = name;
    payrate = p;
    paytype = ptype;
    tot_pay = 0;
    cout << "The value of name is " << name << " the value of ptype is " << ptype << "This is inside employee constructor.\n";
    cout << "Using getname from withiin employee constructor: " << getname() << endl;
    cout << "Using getpayrate() inside employee constructor: " << getpayrate() << endl;
    //cout << "Using getpayrate() inside employee constructor: " << getpaytype() << endl;
    //if the above line is not commented out, the program works
    
}

const string & employee::getname() const
{
    return employee_name;
}

float employee::getpayrate() const
{
    return payrate;
}

const string & employee::getpaytype() const
{
    return paytype;
}

float employee::get_pay()
{
    pay();
    return tot_pay;
}

manager::manager(int Eid, const char * Name, float P, const char * P_type, int Supers)
:employee(Eid,Name,P,P_type),supervisors(Supers)
{
    cout << "The value of name is: " << Name << " The value of P_type is " << P_type << endl;
}

void manager::pay()
{
    tot_pay = payrate + payrate/100*5*getsupervisors();    
}

int manager::getsupervisors() const
{
    return supervisors;
}

void manager::set_supers(int supers)
{
    supervisors = supers;
}
 

Mark44

Joined Nov 26, 2007
628
Your linker error says something about some stuff being referenced in function main. I'm betting that you have a typo in main.

Another little thing that I noticed is that in your employee constructor, the first cout call doesn't have an endl at the end. I don't think this is causing the linker problem, though.
Mark
 

Thread Starter

mentaaal

Joined Oct 17, 2005
451
Hi Mark,
Well its definitely not a typo as if comment out the getpayrate() function in the employee constructor, then i cant use it in main() ! I have tried fiddling with the code in main and its fine. I will include it later as I must have forgotten to include it the first time.

What happens is wherever I reference one of the functions like getpayrate(), the linker complains and gives the location that I have referenced it at.
CRAZY!
 

Thread Starter

mentaaal

Joined Oct 17, 2005
451
There really is nothing wrong with the code in main that i can see anyway.

Rich (BB code):
#include "manager.h"
#include "employee.h"
#include <iostream>
#include <string>
using namespace std;

int main()
{
    manager m1(1,"Greg",3400.0,"Monthly",20);
    
    cout << endl << endl;
    cout << "M1 is getting paid " << m1.get_pay() << endl;
    cout << ((m1.getpaytype() == "monthly")?" per month.\n":" per week.\n");
    cout << m1.getname() << endl;

    cout << m1.getname() << endl;
    cout << m1.getpayrate() << endl;

    

    return 0;
}
 

thatoneguy

Joined Feb 19, 2009
6,359
You left out a word.

In the definitions, you have:
Rich (BB code):
manager::manager(int Eid, const char * Name, float P, const char * P_type, int Supers)
In the class, you have:
Rich (BB code):
manager(int Eid, const char *, float P, const char * P_type, int Supers);
Not sure if it is related, but it might be an issue later on.
 

Thread Starter

mentaaal

Joined Oct 17, 2005
451
Hi, thanks for that, i stuck in Name but it didnt do anything. In the class header, it is allowed to have the prototype empty of names of the variables.

I will ask my lecturer tomorrow and see if he can see why this happening although i doubt it :)
 

Thread Starter

mentaaal

Joined Oct 17, 2005
451
Sure thing, its enclosed in the attachment. Thanks for your help!

I'd happily stick at it myself and I usually do, but i have already been at it for ages, and havent a notion of what it could be
 

Attachments

thatoneguy

Joined Feb 19, 2009
6,359
Your problem is with paytype and scope. Strong hints in bold

You are calling paytype with payrate, also...

Here is the output, I have a different version of studio (08 Enterprise), so project won't export:
Rich (BB code):
The value of name is Greg the value of ptype is Monthly
This is inside employee constructor.
Using getname from withiin employee constructor: Greg
Using getpayrate() inside employee constructor: 3400
Inside constructor, paytype is:  per week.
The value of name is: Greg The value of P_type is Monthly


M1 is getting paid 6800  per week.
Greg
3400
 

Thread Starter

mentaaal

Joined Oct 17, 2005
451
Well I cannot for the life of me see the problem, I noticed your message and tried it again myself but the results of the cout in the constructor say monthly as well as the couts in main.

I have re-written the entire thing from scratch and it works problem free. I am guessing I have made some weird typo or mistake somewhere and just cant see it. I shudder to think how difficult it must be to debug thousands of lines of code in industry.

Edit: This is unbelievable! It happened again on my new program and I am back to square one again. Could you give me a bigger hint as to what the problem is? Its driving me nuts!

Rich (BB code):
#ifndef EMPLOYEE_H
#define EMPLOYEE_H

#include <string>
using namespace std;

//Given the following class which will be used as the base class to represent a assembly line in a local factory:

class employee
{
public:
  employee(int id, string name, float p);
  inline const string & getname() const;
  inline float getpayrate() const;
  virtual float pay(float hours) const =0; //ensures that employee is abstract and cannot be instantiated. 

protected:
  int employee_id;
  string emp_name;
  float payrate;
};

#endif
/*Create 3 other classes that are derived from the class employee:

manager - is a salaried wage, looks after a supervisor
supervisor - is a salaried wage, looks after several line employees
line_employee - is a weekly wage

You are required to write the complete C++ program to test your base and derived classes. 
Feel free to add any member functions or variables to the derived classes to further demonstrate your knowledge of inheritance.*/
Rich (BB code):
#include "employee.h"
#include <iostream>
using namespace std;
employee::employee(int id, std::string name, float p)
:employee_id(id),emp_name(name),payrate(p)
{
    //cout << "this is a test.\n";
    //cout << getname() << endl;
    //cout << getpayrate() << endl;
}

const string & employee::getname() const
{
    return emp_name;
}

float employee::getpayrate() const
{
    return payrate;
}
Rich (BB code):
#ifndef MANAGER_H
#define MANAGER_H

#include "employee.h"

class manager : public employee //derived class of employee
{
public:
    manager(int Id, string Name, float P, int sups);
    inline int get_sups() const;
    virtual float pay(float hours) const; //function overload

private:
    int supervisors;

};

#endif
Rich (BB code):
#include "manager.h"

manager::manager(int Id, std::string Name, float P, int sups)
:employee(Id,Name,P),supervisors(sups)
{}

int manager::get_sups() const
{
    return supervisors;
}

float manager::pay(float hours) const
{
    return hours*payrate + payrate/100*8*supervisors*hours;
}
Rich (BB code):
#include <iostream>
using namespace std;

#include "employee.h"
#include "manager.h"

int main()
{
    manager test(1,"blah",20.0,20);
    cout << test.getname() << test.getpayrate() << endl;
    
    
    return 0;
}
Well I am going to put this problem down to the compiler being stupid. In the very first program, what i had to change to make this work was: revoving the inline const string & and replace with just string for getname and getpayrate. Funnily enough when I replace the function with how it was before, i.e. inline const string &, it works perfectly, but here is the kicker:

WHEN I PUT IT ALL BACK IN AS SAID, THEN GO TO COMPILE IT WHILST THE DEFINITION WINDOW IS OPEN AS OPPOSED TO THE HEADER WINDOW, THE PROGRAM REVERTS BACK TO THE DISCUSSED ERRORS!

I have narrowed it down to the inline function, when i add the inline function to the prototype, the compiler says:
Skipping... (no relevant changes detected)
but when i change the view to the definition file, the error is back. And the really funny thing is, if I then remove the inline function, and to to recompile it whilst looking at the header, the compiler still issues the error, then only way to get rid of it then is to go back to the definition file and compile it there!

Could someone explain this response to me or is it a bug? Is it allowed to say:
inline const string & function_name(int argument);

Edit: a similar occurrence happens if manually rebuilding the solution is done. For some reason, the compiler skips rebuilding the project after putting in inline if still in the header, but when another file is viewed, the project is rebuilt and the error issued.
 
Last edited:

Mark44

Joined Nov 26, 2007
628
There really is nothing wrong with the code in main that i can see anyway.

Rich (BB code):
#include "manager.h"
#include "employee.h"
#include <iostream>
#include <string>
using namespace std;

int main()
{
    manager m1(1,"Greg",3400.0,"Monthly",20);
    
    cout << endl << endl;
    cout << "M1 is getting paid " << m1.get_pay() << endl;
    cout << ((m1.getpaytype() == "monthly")?" per month.\n":" per week.\n");
    cout << m1.getname() << endl;

    cout << m1.getname() << endl;
    cout << m1.getpayrate() << endl;

    

    return 0;
}
I'm pretty sure the comparison here is your problem:
Rich (BB code):
cout << ((m1.getpaytype() == "monthly")?" per month.\n":" per week.\n");
m1.getpaytype() evaluates to a string, as does "monthly". The value of a string literal is its address in memory, NOT the value of the characters in the string. Since you're using the <string> header, I don't think it offers a function to compare strings (although it might), in which case you'll need to use a standard library function such as strcmp() to make the comparison.

Mark
 

thatoneguy

Joined Feb 19, 2009
6,359
Try this in the class where you output tests:

Rich (BB code):
#include "employee.h"
#include <iostream>
using namespace std;
employee::employee(int id, std::string name, float p)
:employee_id(id),emp_name(name),payrate(p)
{
    cout << "this is a test.\n";
    cout << getname() << endl;
    cout << getpayrate() << endl;
    cout << getpaytype() << endl;

}

const string & employee::getname() const
{
    return emp_name;
}

float employee::getpayrate() const
{
    return payrate;
}
 

thatoneguy

Joined Feb 19, 2009
6,359
Here's the source for what worked, never thought of just posting it:rolleyes::

application
Rich (BB code):
#include "manager.h"
#include "employee.h"
#include <iostream>
#include <string>
using namespace std;

int main()
{
    manager m1(1,"Greg",3400.0,"Monthly",20);
    
    cout << endl << endl;
    cout << "M1 is getting paid " << m1.get_pay() << " ";
    cout << ((m1.getpaytype() == "monthly")?" per month.\n":" per week.\n");
    cout << m1.getname() << endl;
    cout << m1.getpayrate() << endl;

    

    return 0;
}

employee-definition
Rich (BB code):
#include "employee.h"

employee::employee(int eid, const char* name, float p, const char * ptype)
{
    employee_id = eid;
    employee_name = name;
    payrate = p;
    paytype = ptype;
    tot_pay = 0;
    cout << "The value of name is " << name << " the value of ptype is " << ptype << "This is inside employee constructor.\n";
    cout << "Using getname from withiin employee constructor: " << getname() << endl;
    cout << "Using getpayrate() inside employee constructor: " << getpayrate() << endl << "Inside constructor, paytype is: " ;
    cout << ((getpaytype() == "monthly")?" per month.\n":" per week.\n");
    
}

const string & employee::getname() const
{
    return employee_name;
}

float employee::getpayrate() const
{
    return payrate;
}

const string & employee::getpaytype() const
{
    return paytype;
}

float employee::get_pay()
{
    pay();
    return tot_pay;
}

mgr-def
Rich (BB code):
#include "manager.h"

manager::manager(int Eid, const char * Name, float P, const char * P_type, int Supers)
:employee(Eid,Name,P,P_type),supervisors(Supers)
{
    cout << "The value of name is: " << Name << " The value of P_type is " << P_type << endl;
}

void manager::pay()
{
    tot_pay = payrate + payrate/100*5*getsupervisors();    
}

int manager::getsupervisors() const
{
    return supervisors;
}

void manager::set_supers(int supers)
{
    supervisors = supers;
}
 

Thread Starter

mentaaal

Joined Oct 17, 2005
451
Hey guys, thanks for the additional posts, much appreciated. Well I am not sure if you saw my last message, I had edited my last post as opposed to just replying again but it turns out that the inline function was causing the problems! I dont understand why or how but that was it. const string & doesnt work with inline perhaps?
 
Top