0

I have an odd situation here and can't figure it out. I am trying to create a static const string variable in each class and retrieve it with a getter, however I'm getting the error message:

|39|undefined reference to `Commercial::type'|

I have a very large project with lots of files so I will post the section that I am having trouble with and hopefully it is enough.

Commercial.h file:

#ifndef __COMMERCIAL_H__
#define __COMMERCIAL_H__


#include "property.h"

class Commercial :  public virtual Property
{
private:
  static const string type;

protected:
  string license;

public:

  Commercial();
  Commercial(string theOwner, string theAddress, string theSuburb,
              int thepostCode, string theLicense);

   ~Commercial() ;

   Commercial(const Commercial& orig);

  void input() ;   // Data input for a Shop object
  void print() ;  // Data output for a Shop object
  bool isProperty(Property& other);

  string getLicense() const {return license;};   //Note the use of const

  void setLicense(string theLicense) {license = theLicense;};

  const string getType() const {return type;};

  static void setType() {const string type = "Commercial";};
};

#endif

Commercial.cpp file:

#include "commercial.h"


Commercial::Commercial() : Property() {
   owner = "NULL";
   address = "NULL";
   suburb = "NULL";
   postcode = 0;
   license = "NULL";
}

Commercial::Commercial(string theOwner, string theAddress,
                        string theSuburb, int thepostCode,
                        string theLicense): Property(theOwner, theAddress,
                        theSuburb, thepostCode), license(theLicense) {}

Commercial::~Commercial() {}

Commercial::Commercial(const Commercial& orig) : Property(orig),
                        license(orig.getLicense()) {}

void Commercial::print() {
   cout << getOwner() << endl;
   cout << getAddress() << endl;
   cout << getSuburb() << endl;
   cout << getPostcode() << endl;
   cout << getLicense() << endl;
}

void Commercial::input() {

   string tempOwner;
   string tempAddress;
   string tempSuburb;
   int tempPostcode;
   string tempLicense;

   cout << endl;

   do {
      cout << "Enter The Owner: ";
      getline(cin, tempOwner, '\n');
   } while (cin.fail());

   do {
      cout << "Enter The Address: ";
      getline(cin, tempAddress, '\n');
   } while (cin.fail());

   do {
      cout << "Enter The Suburb: ";
      getline(cin, tempSuburb, '\n');
   } while (cin.fail());

   for (;;) {
      cout << "Enter The Postcode: ";
      cin >> tempPostcode;
      if ((cin)) {
         clearInputBuffer();
         break;
      }
      cin.clear();
      cin.ignore(numeric_limits<streamsize>::max(), '\n');
   }

   do {
      cout << "Enter The License: ";
      getline(cin, tempLicense, '\n');
   } while (cin.fail());

   setOwner(tempOwner);
   setAddress(tempAddress);
   setSuburb(tempSuburb);
   setPostcode(tempPostcode);
   setLicense(tempLicense);
}

bool Commercial::isProperty(Property& other) {

   if (typeid(other) == typeid(Commercial)) {
      return true;
   }

   return false;
}

property.h file:

#ifndef __PROPERTY_H__
#define __PROPERTY_H__


/*TODO  REQUIRED HEADER FILES AND NAMESPACES*/
#include <string>
#include "utility1.h"

class Property
{
private:
  static const string type;

protected:
  string owner;
  string address;
  string suburb;
  int postcode;

public:
  Property();
  Property(string theOwner, string theAddress,
           string theSuburb, int thepostCode);
  virtual ~Property();
  Property(const Property& orig);
  virtual void input() = 0;   // Data input for a Property object
  virtual void print() = 0;  // Data output for a Property object
  virtual bool isProperty(Property& other) = 0;

  string getOwner() const {return owner;};   //Note the use of const
  string getAddress() const {return address;};
  string getSuburb() const {return suburb;};
  int getPostcode() const {return postcode;};

  void setOwner(string newOwner) {owner = newOwner;};
  void setAddress(string newAddress) {address = newAddress;};
  void setSuburb( string  newSuburb) {suburb = newSuburb;};
  void setPostcode(int  newPostcode) {postcode = newPostcode;};

  virtual const string getType() const {return type;};

// Un-needed and pointless, just done to make the compiler happy.
  static void setType() {const string type = "Property";};
};
#endif

Property.c file:

#include "property.h"

Property::Property(){
   owner = "NULL";
   address = "NULL";
   suburb = "NULL";
   postcode = 0;
}

Property::Property(string theOwner, string theAddress,
                   string theSuburb, int thepostCode):
                     owner(theOwner), address(theAddress),
                     suburb(theSuburb), postcode(thepostCode){}

Property::~Property() {}

Property::Property(const Property& orig) :
                     owner(orig.getOwner()), address(orig.getAddress()),
                     suburb(orig.getSuburb()), postcode(getPostcode()) {}

void Property::print() {
   cout << getOwner() << endl;
   cout << getAddress() << endl;
   cout << getSuburb() << endl;
   cout << getPostcode() << endl;
}

void Property::input() {

   string tempOwner;
   string tempAddress;
   string tempSuburb;
   int tempPostcode;

   cout << endl;

   do {
      cout << "Enter The Owner: ";
      getline(cin, tempOwner, '\n');
   } while (cin.fail());

   do {
      cout << "Enter The Address: ";
      getline(cin, tempAddress, '\n');
   } while (cin.fail());

   do {
      cout << "Enter The Suburb: ";
      getline(cin, tempSuburb, '\n');
   } while (cin.fail());

   for (;;) {
      cout << "Enter The Postcode: ";
      cin >> tempPostcode;
      if ((cin)) {
         clearInputBuffer();
         break;
      }
      cin.clear();
      cin.ignore(numeric_limits<streamsize>::max(), '\n');
   }

   setOwner(tempOwner);
   setAddress(tempAddress);
   setSuburb(tempSuburb);
   setPostcode(tempPostcode);
}

Test / Driver .cpp file:

#include "property.h"
#include "utility1.h"
#include "rentals.h"
#include "commercial.h"
#include "sales.h"
#include "comSales.h"
#include "resSales.h"
#include "resRentals.h"
#include "comRentals.h"

void testingNewFunction(Property* properties[]);

const int MAX_PROPERTIES = 5;

int main(void) {
   int typeCount = 0;

   Property *properties[MAX_PROPERTIES];

   properties[0] = new Commercial("Notting Hill McDonalds", "4 Gardiner Road",
                                  "Notting Hill", 5000, "Li3000");

   properties[1] = new ResRentals("Janet Dalgleish", "30 Firhill Court",
                           "Mary Hill", 4000, 500.00, 300.00, 4);

   properties[2] = new Commercial();
   properties[2] = properties[0];

   properties[3] = new ComSales();
   properties[3]->input();

   properties[4] = new ComRentals();
   properties[4]->setOwner("River Kwai Restaurant");
   properties[4]->setAddress("3 Bishopton Road");
   properties[4]->setSuburb("Footscray");
   properties[4]->setPostcode(5000);
   dynamic_cast<Commercial*>(properties[4])->setLicense("L8888");
   dynamic_cast<Rentals*>(properties[4])->setBond(10000);
   dynamic_cast<Rentals*>(properties[4])->setMonthlyRent(700);


   cout << endl;

   for (int i = 0; i < MAX_PROPERTIES; i++) {

      ComSales* tempType = new ComSales();

      if (properties[i]->isProperty(*dynamic_cast<ComSales*>(tempType))) {
         typeCount++;
      }
      if (i == MAX_PROPERTIES-1) {
         cout << typeCount << " ComSales" << endl;
         typeCount = 0;
      }
   }


   for (int i = 0; i < MAX_PROPERTIES; i++) {

      ComRentals* tempType = new ComRentals();

      if (properties[i]->isProperty(*dynamic_cast<ComRentals*>(tempType))) {
         typeCount++;
      }
      if (i == MAX_PROPERTIES-1) {
         cout << typeCount << " ComRentals" << endl;
         typeCount = 0;
      }
   }


   for (int i = 0; i < MAX_PROPERTIES; i++) {

      ResSales* tempType = new ResSales();

      if (properties[i]->isProperty(*dynamic_cast<ResSales*>(tempType))) {
         typeCount++;
      }
      if (i == MAX_PROPERTIES-1) {
         cout << typeCount << " ResSales" << endl;
         typeCount = 0;
      }
   }


   for (int i = 0; i < MAX_PROPERTIES; i++) {
      cout << properties[i]->getOwner() << " is a "
      << typeid(*properties[i]).name() << endl;
   }


   testingNewFunction(&properties[MAX_PROPERTIES]);

   return 0;
}

void testingNewFunction(Property* properties[]) {

   // Initializing static variables (normally would be done in a separate
   // function).
   Commercial::setType();
   ComRentals::setType();
   ComSales::setType();
   Property::setType();
   Rentals::setType();
   Residential::setType();
   ResRentals::setType();
   ResSales::setType();
   Sales::setType();

   int comRentalsCount = 0;
   int comSalesCount = 0;
   int ResSalesCount = 0;

   for (int i = 0; i < MAX_PROPERTIES; i++) {
      const string tempType = properties[i]->getType(); //<--- trying to access the type string for each property in the array
                                                        // which is saying the reference is undefined.
   }


}

the layout is odd due to it being take from a school assignment, I am messing around testing new ways to do things with it. please help with this :)

EDIT: this question was marked as a duplicated however the question stated that it was a duplicate of doesn't help anything to do with this as it is all about linking errors and I can not see anything to do with that on my question, if it is please be specific as to why it is.

Thanks in advance.

Rory Thoman
  • 69
  • 12
  • `static const string type;` is a declaration, and not a definition. See [this answer](http://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix/12574407#12574407). – chris Apr 18 '15 at 02:09
  • it is defined by 'setType()' functions, in my main cpp function – Rory Thoman Apr 18 '15 at 02:11
  • I fail to see how the answer I linked (which is the relevant part of that dupe) doesn't help. "*however, odr-use of this member will still require a namespace scope definition as described above*" There's no `set` function, and no `Class::set;` line. Like the answer says, it has to be defined at namespace scope, and in one translation unit (so your Commercial.cpp file is a good choice). – chris Apr 18 '15 at 02:18
  • That duplicated question does not help me at all since they ARE defined, can you help me pin point where it is not cause I can only see that they are – Rory Thoman Apr 18 '15 at 02:18
  • const string getType() const {return type;}; is that not both a declaration AND definition? it works perfectly well with setLicense and getLicense, i dont understand the difference between these two functions – Rory Thoman Apr 18 '15 at 02:20
  • @RoryThoman They are not defined, only declared — you need `const string Property::type;`in Property.cpp, and similar for the other classes. – molbdnilo Apr 18 '15 at 02:21
  • Yes, that declares and defines the `getType` member function. However, static data members are different in that the declaration inside the class is not a definition, and most uses of that data member require a separate definition. You can read more about why [in this question](http://programmers.stackexchange.com/questions/145299/why-the-static-data-members-have-to-be-defined-outside-the-class-separately-in-c). – chris Apr 18 '15 at 02:22
  • Commercial::setType(); does not do this? what shall I write to define Commercial::type then inside the Commercial.cpp and similar files? – Rory Thoman Apr 18 '15 at 02:24
  • @RoryThoman Your `setType` functions assign to local variables, which are different from the static members. That doesn't cause the static members to become defined. – molbdnilo Apr 18 '15 at 02:24
  • Ok thanks, but how would I define this particular static variable in the Commercial.cpp file since it is private? – Rory Thoman Apr 18 '15 at 02:27
  • @RoryThoman, The `setType` function creates a new local variable that shadows your data member. I believe the option for GCC and Clang to warn here is `-Wshadow` if you want to see. Both molbdnilo and the linked answer have the correct syntax. `Type ClassName::memberName;`. Accessibility doesn't play a role in defining these, so it being private is not an issue. – chris Apr 18 '15 at 02:28
  • after a bit of looking at the other question is this correct then? const string Commercial::type = "Commercial"; in the Commercial.cpp file? also, does this mean for my situation I don't need the setter and associated declaration function? – Rory Thoman Apr 18 '15 at 02:31
  • @RoryThoman, Correct. One thing I have to say is that I'm questioning the need for the member. The virtual `getType` function is good enough on its own, just returning the appropriate string literal. – chris Apr 18 '15 at 02:41
  • It's all experimentation, what works, what doesn't, what's best, what's not etc. for example, this was a way to define, return and compare private static strings. thanks for the help have it working now. – Rory Thoman Apr 18 '15 at 02:53

0 Answers0