-2

I'm getting a LNK 2019 and 2001 error every time I compile. LNK2019 states:

public: __thiscall ColMbr::ColMbr(unsigned int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0ColMbr@@QAE@IV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "public: __thiscall Alumni::Alumni(unsigned int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,int,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0Alumni@@QAE@IV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@HHH0@Z

So there is some kind of error linking ColMbr class with Alumni. LNK2011 says:

"public: virtual void __thiscall Alumni::addClass(unsigned int,unsigned int)" (?addClass@Alumni@@UAEXII@Z)

So there's an issue with my virtual function call. I understand that the LNK errors means there was a variable that needed to be declared that I missed but I don't see it. Firstly, the Alumni::addClass function is just there to make sure Alumni does not become an abstract class like ColMbr, which it's derived from. Secondly, all of the arguments in Alumni are defined and declared either in Alumni or in ColMbr.

If it was anything I'd say LNK2019 is probably a problem with my const unsigned int idNbr. I don't know what's wrong with LNK2001. Maybe I need to give the function a garbage purpose or something.

This is my header file followed by the cpp.

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

#ifndef _ColMbr
#define _ColMbr
class ColMbr
{
protected:
    const unsigned int idNbr;
    std::string name;
public:
    ColMbr();
    ColMbr(const unsigned int idNbr, std::string stdnt_name);
    std::string setName(std::string stdnt_name);
    virtual void display(void);
    virtual void addClass(unsigned int credits, unsigned int gradePoint) = 0;
};
#endif // !1

std::string ColMbr::setName(std::string stdnt_name)
        {
            name = stdnt_name;
            return name;
        }

class Student : public ColMbr
{
private:
    unsigned int credHrs, qualPts;
    std::string degSought;
    double GPA;
public:
    Student(unsigned int idNbr, std::string name) : ColMbr (idNbr, name)
    {
        credHrs = 0;
        qualPts = 0;
        degSought = "Unspecified";
    }
    Student(const unsigned int idNbr, std::string stdnt_name, unsigned int credHrs1, unsigned int qualPts1, std::string newDegree) : ColMbr(idNbr,stdnt_name)
    {
        credHrs = credHrs1;
        qualPts = qualPts1;
        degSought = newDegree;
    }
    void setDegree(std:: string newDegree);
    double getGPA(unsigned int credHrs, unsigned int qualPts);
    void addClass(unsigned int newClass, unsigned int newQualPts)
    {
        credHrs = credHrs + newClass;
        qualPts = qualPts + newQualPts;
    }
    void display(void)
    {
        std::cout << "This student is active." << std::endl <<"ID #: "
            << idNbr << std::endl << "Name: " << name << std::endl
            << "GPA: " << GPA << std::endl << "Major: " << degSought
            << std::endl;
    }
};

void Student::setDegree(std:: string newDegree)
{
    degSought = newDegree;
}
double Student::getGPA(unsigned int credHrs, unsigned int qualPts)
{
    double credHrs1, qualPts1;
    std::istringstream input(credHrs);
    input >> credHrs1;
    std::istringstream input1(qualPts);
    input >> qualPts1;
    GPA = qualPts1 / credHrs1;
    return GPA;
}

#ifndef _Alumni
#define _Alumni
class Alumni : public ColMbr
{
private:
    std::string degree;
    int month, day, year;
public:
    Alumni(const unsigned int idNbr, std::string stdnt_name, int gradMonth, int gradDay, int gradYear, std::string newDegree) : ColMbr(idNbr, stdnt_name)
    {
        degree = newDegree;
        month = gradMonth;
        day = gradDay;
        year = gradYear;
    }
    void addClass(unsigned int credits, unsigned int gradePoint);
    void display (void)
    {
        std::cout << "This student is an Alumni." << std::endl <<"ID #: "
                << idNbr << std::endl << "Name: " << name << std::endl
                << "Graduation Date: " << month << "/" << day << "/" << year 
                << std::endl << "Major: " << degree << std::endl;
    }
};
#endif

/**********************************************

#include <iostream> 
#include <cstdlib> 
#include "ColMbrs.h" 


int main() 
{ 
    ColMbr *cMbr[4]; // array of base-class pointers 
    int i; // index to array 

 // Create some college members 

    cMbr[0] = new Student( 12345, "Steven DiFranco", 15, 33, "AA" ); 
    cMbr[1] = new Alumni( 98765, "Don Green", 12, 15, 1978, "AAS" ); 
    cMbr[2] = new Alumni( 24680, "Henry Thoreau", 5, 22, 1846, "AA" ); 
    cMbr[3] = new Student( 13579, "Millenia Best" ); 

 // display the array 

    cout << "All college members:\n"; 
    for( i = 0; i < 4; ++i ) 
    { 
        cMbr[i]->display(); // no need to check type field or cast 
        cout << endl; 
    } 

 // test addClass for student 

    cMbr[3]->addClass( 3, 12 ); 
    cMbr[3]->display(); 

    cout << endl; 
    system("PAUSE"); 
    return 0; 
} 
László Papp
  • 51,870
  • 39
  • 111
  • 135
Spitz
  • 63
  • 1
  • 9
  • You have declarations for those functions but you have not implemented them. You need to do that. – Retired Ninja Apr 07 '14 at 04:44
  • Thanks, that helped a lot. So, I copied Alumni::addClass and declared it outside the function. That got rid of LNK2001. You can't pull the constructor out of the class definition though. What would you have to implement from the constructor to get around the error? – Spitz Apr 07 '14 at 04:59
  • Where is the implementation of your ctor? – László Papp Apr 07 '14 at 05:02
  • I'm not exactly sure what you mean by implementation. The ColMbr class and constructor simply serve as the base class for Student and Alumni. ColMbr is an abstract class that simply passes its variables and functions to the derived classes. After adding the brackets VS says that my const int needs to be initialized, which doesn't make any sense to me because it's being initialized by input to the constructor from the cpp file. – Spitz Apr 07 '14 at 21:10
  • I mean, if I initialize the const then it can't change and I won't have individual ID #s for each object. – Spitz Apr 07 '14 at 21:22
  • I wonder if this question is useful for anyone apart from the OP. – László Papp May 23 '14 at 12:20

1 Answers1

0

So, this is how I got my code to compile and run correctly.

I declared both the constructor and the function that were giving me problems outside the class. After that I had to put an assignment for GPA from the GPA function into the Student::display(void) function. Finally, I couldn't figure out how to initialize the const unsigned in idNbr in the ColMbr class from the ColMbr(const unsigned int idNbr, std::string stdnt_name) constructor so I took the const label off the variable.

Here's the code for the header file. The .cpp remains the same.

Edited to reflect how I solved const unsigned int idNbr problem.

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

#ifndef _ColMbr
#define _ColMbr
class ColMbr
{
protected:
    unsigned const int idNbr;
    std::string name;
public:
    //A default and initial constructor are called.
    ColMbr();
    ColMbr(const unsigned int id, std::string stdnt_name) : idNbr(id)
    {
        name = setName(stdnt_name);
    }
    virtual ~ColMbr();
    std::string setName(std::string stdnt_name);
    //ColMbr is made into an abstract class.  It can not be called except with
    //a pointer.
    virtual void display(void);
    virtual void addClass(unsigned int credits, unsigned int gradePoint) = 0;
};
#endif // !1

ColMbr::~ColMbr(){}

void ColMbr::display(void)
{
}

std::string ColMbr::setName(std::string stdnt_name)
        {
            name = stdnt_name;
            return name;
        }

class Student : public ColMbr
{
private:
    unsigned int credHrs, qualPts;
    std::string degSought;
    double GPA;
public:
    //A constructor with no additional Student attributes is created.
    Student(unsigned int idNbr, std::string name) : ColMbr (idNbr, name)
    {
        credHrs = 0;
        qualPts = 0;
        degSought = "Unspecified";
    }
    //A constructor that adds Student attributes is created.
    Student(const unsigned int idNbr, std::string stdnt_name, unsigned int credHrs1, unsigned int qualPts1, std::string newDegree) : ColMbr(idNbr,stdnt_name)
    {
        credHrs = credHrs1;
        qualPts = qualPts1;
        degSought = newDegree;
    }
    ~Student();
    //Functions for initializing the variables that will be output.
    void setDegree(std:: string newDegree);
    static double getGPA(unsigned int credHrs, unsigned int qualPts);
    //The virtual functions are overwritten.  Addclass allows for a change in GPA.
    void addClass(unsigned int newClass, unsigned int newQualPts)
    {       
        credHrs = credHrs + newClass;
        qualPts = qualPts + newQualPts;
    }
    void display(void)
    {
        GPA = getGPA(credHrs, qualPts);
        std::cout << "This student is active." << std::endl <<"ID #: "
            << idNbr << std::endl << "Name: " << name << std::endl
            << "GPA: " << GPA << std::endl << "Major: " << degSought
            << std::endl;
    }
};

Student::~Student(){}

void Student::setDegree(std:: string newDegree)
{
    degSought = newDegree;
}
//getGPA is declared and new students receive a 0
double Student::getGPA(unsigned int credHrs, unsigned int qualPts)
{
    double GPA;
    double credHrs1, qualPts1;
    if (credHrs == 0)
    {
        GPA = 0;
    }
    else
    {
        credHrs1 = static_cast<double>(credHrs);
        qualPts1 = static_cast<double>(qualPts);
        GPA = qualPts1 / credHrs1;
    }
    return GPA;
}

#ifndef _Alumni
#define _Alumni
class Alumni : public ColMbr
{
private:
    std::string degree;
    int month, day, year;
public:
    //An alumni constructor is defined.
    Alumni(const unsigned int idNbr, std::string stdnt_name, int gradMonth, int gradDay, int gradYear, std::string newDegree) : ColMbr(idNbr, stdnt_name)
    {
        degree = newDegree;
        month = gradMonth;
        day = gradDay;
        year = gradYear;
    }
    ~Alumni();
    //The virtual classes are overwritted.
    //Even though addClass has no function here it is overwritten to ensure Alumni is not an abstract class.
    void addClass(unsigned int credits, unsigned int gradePoint);
    void display (void)
    {
        std::cout << "This student is an Alumni." << std::endl <<"ID #: "
                << idNbr << std::endl << "Name: " << name << std::endl
                << "Graduation Date: " << month << "/" << day << "/" << year 
                << std::endl << "Major: " << degree << std::endl;
    }
};
#endif

Alumni::~Alumni(){}

void Alumni::addClass(unsigned int credits, unsigned int gradePoint)
{}
Spitz
  • 63
  • 1
  • 9
  • I just figured out how to initialize the unsigned int. You use this in the constructor definition: `ColMbr(const unsigned int id, std::string stdnt_name) : idNbr(id)` So I took the Constructor declaration out and moved the setName call into the Constructor definition body. It all works now. Credit to http://stackoverflow.com/questions/3904759/how-can-i-initialize-a-const-variable-of-a-base-class-in-a-derived-class-constr and Konrad Rudolph for the help. – Spitz Apr 08 '14 at 01:36