0
votes

I get a strange error all the time.

/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:

In function _start: >(.text+0x20): undefined reference to main /tmp/cc4ZqKzy.o:

In function `Sep::Building::Building(Sep::Field::FieldType, >std::__cxx11::basic_string, >std::allocator >, char, bool, bool, unsigned int, unsigned int):

Building.cpp:(.text+0x3c): undefined reference to Sep::Field::Field() collect2:

error: ld returned 1 exit status

I read a lot with this problem but none had the same. I included all the headers and also added ifndef guards.

main.cpp:

#include "Field.h"
#include "Building.h"

namespace Sep
{
  just some returns...
}

int main(int argc, char *argv[])
{
  Sep::Building Haus(Sep::Field::FieldType::HOME,"HOME", 'H', true, true, 100, 100);
  std::cout << "HAUS ABREV:" << Haus.getAbbrevationOnField() << '\n';
}

Field.h

#include <cstring>
#include <string>
#include <iostream>
#include <memory>


#ifndef FIELD_H
#define FIELD_H

namespace Sep
{

  //----------------------------------------------------------------------------
  // Field class, containing all needed information to create a Field object
  //
  class Field
  {
    public :
      enum FieldType \
      {GRASS, WATER, OBSTACLE, STREET, HOME, MARKET, CLINIC, TOWNHALL};

    private:
      FieldType type_;
      std::string name_;
      char abbrevation_;
      bool buildable_;
      bool destroyable_;
      unsigned int build_cost_;
      unsigned int destroy_cost_;

    public:
      //------------------------------------------------------------------------
      // Field constructors & destructor
      //
      Field();
      Field(FieldType type);
      ~Field() noexcept;
      //------------------------------------------------------------------------
      //getters
      //
      Field::FieldType getFieldType() const { return type_; };
      const char getAbbrevationOnField() const { return abbrevation_; };

  //------------------------------------------------------------------------
  //setters
  //
      static std::string getName(FieldType type);
      FieldType getType() const;//steht oben in getFiel3dType Z55

      void setType(FieldType type){type_ = type;};
      void setName(std::string name){name_ = name;};
      void setAbbrevation(char abbrev){abbrevation_ = abbrev;};
      void setBuildable(bool buildable){buildable_ = buildable;};
      void setDestroyable(bool destroyable){destroyable_ = destroyable;};
      void setBuildCost(int b_cost){build_cost_ = b_cost;};
      void setDestroyCost(int d_cost){destroy_cost_ = d_cost;};
  };
}

#endif //FIELD.H

Field.cpp

#include "Field.h"
#include <cstring>
#include <string>
#include <iostream>
#include <memory>

using Sep::Field;


//------------------------------------------------------------------------------
// Setter of the private FieldType type_ to the given param
//
// @param the type of field to get set
//
Field::Field(FieldType type)
{
  type_ = type;
};

Field::~Field(){};

//------------------------------------------------------------------------------
// Checks the type of a given field, returns the name of type as string
//
// @param type, the type of the field to check
//
// @return string the name of the type of the checked field
//
std::string Field::getName(FieldType type)
{
  switch (type)
  {
    case GRASS:
      return std::string("Grass");
    case WATER:
      return std::string("Water");
    case OBSTACLE:
      return std::string("Obstacle");
    case STREET:
      return std::string("Street");
    case HOME:
      return std::string("Home");
    case MARKET:
      return std::string("Market");
    case CLINIC:
      return std::string("Clinic");
    case TOWNHALL:
      return std::string("Town Hall");
    default:
      return std::string("Unknown Field");
  }
};

//------------------------------------------------------------------------------
// getters
//
// Getter from the private FieldType type_
//
// @param none
//
// @return the type of type_ as FieldType
//
Field::FieldType Field::getType() const
{
  return type_;
};

Building.h

#ifndef BUILDING_H
#define BUILDING_H

#include "Field.h"

namespace Sep
{
  class Building : public Field
  {
    private:

    public:
    Building(FieldType type, const std::string name, const char abbrevation, \
           const bool buildable, const bool destroyable,\
           const unsigned int b_cost, const unsigned int d_cost);
    ~Building();
  };
}

#endif //BUILDING_H

Building.cpp

#include "Building.h"
#include "Field.h"

Sep::Building::Building(FieldType type, const std::string name, \
         const char abbrevation, \
         const bool buildable, const bool destroyable,\
         const unsigned int b_cost, const unsigned int d_cost)
{
  Sep::Field::setType(type);
  Sep::Field::setName(name);
  Sep::Field::setAbbrevation(abbrevation);
  Sep::Field::setBuildable(buildable);
  Sep::Field::setDestroyable(destroyable);
  Sep::Field::setBuildCost(b_cost);
  Sep::Field::setDestroyCost(d_cost);
};

Sep::Building::~Building(){};

Has anyone a idea? Cause I get this error often in this project but in other classes. The strange thing is that it seems like, that the program compiles correctly but on the start I get this collect2: error: ld returned 1 exit status.

Thx

2
Field.cpp has no implementation for the default constructor Field();Cory Kramer

2 Answers

2
votes

Field.cpp need to be changed, if don't want to used Field() constructor just put the definition of Field() constructor empty.

For examples: Field.cpp

#include "Field.h"
#include <cstring>
#include <string>
#include <iostream>
#include <memory>

using Sep::Field;


//------------------------------------------------------------------------------
// Setter of the private FieldType type_ to the given param
//
// @param the type of field to get set
//
Field::Field(){ 

       //empty constructor or can initialize type_ to default value.
   }


Field::Field(FieldType type)
{
  type_ = type;
};

Field::~Field(){};

//------------------------------------------------------------------------------
// Checks the type of a given field, returns the name of type as string
//
// @param type, the type of the field to check
//
// @return string the name of the type of the checked field
//
std::string Field::getName(FieldType type)
{
  switch (type)
  {
    case GRASS:
      return std::string("Grass");
    case WATER:
      return std::string("Water");
    case OBSTACLE:
      return std::string("Obstacle");
    case STREET:
      return std::string("Street");
    case HOME:
      return std::string("Home");
    case MARKET:
      return std::string("Market");
    case CLINIC:
      return std::string("Clinic");
    case TOWNHALL:
      return std::string("Town Hall");
    default:
      return std::string("Unknown Field");
  }
};

//------------------------------------------------------------------------------
// getters
//
// Getter from the private FieldType type_
//
// @param none
//
// @return the type of type_ as FieldType
//
Field::FieldType Field::getType() const
{
  return type_;
};
2
votes

When you are trying to construct a Building, the Building::Building(...) constructor implicitly calls its base class constructor Field::Field() (since you did not specify which Field constructor you want). You promised in Field.h that such a constructor exists somewhere (which is why the compiler never complains), but you never define it. When the linker then tries to link the functions you declared with the functions that the compiler emitted, it notices that this constructor is missing and complains.

This is what the error messages are trying to tell you:

  • undefined reference to 'Sep::Field::Field()' -> The Field::Field() constructor is not defined anywhere.

  • In function Sep::Building::Building(...) -> It is trying to call the Field constructor in the shown Building constructor.

The simplest fix is to write Field() = default; so the compiler automatically generates the default constructor.

Edit: If you want to use the Field::Field(FieldType) constructor, this is how you would do that:

Building::Building(FieldType fieldType, /* etc */)
  : Field(fieldType)
{
  // etc.
}

You could also add a constructor to the Field class that takes all these arguments that you are trying to pass:

Field::Field(FieldType fieldType, std::string name, char abbrevation, /* etc. */)
  : type_(fieldType), name_(name), abbrevation_(abbreviation), /* etc. */
{
}

And thus:

Building::Building(FieldType type, const std::string name, const char abbrevation, /* etc. */)
  : Field(type, name, abbreviation, /* etc. */)
{
}

Even better, you can just "reuse" the long Field constructor for Building

class Building : public Field
{
public:
  using Field::Field;

  // ...
}