0

I've an issue and I can't solve it (with google). As practice I write a program about chess. There is a general piece class:

pieces.h :

#ifndef PIECES_H
#define PIECES_H

[...]

class piece{
public:
    bool dark; //0 = light, 1 = dark
    virtual std::vector<position> sovereign_movement();
    types identify; // enum types = {pawn, knight, king, etc...}
    position pos;
    std::vector<position> horizontal(position a);
    std::vector<position> vertical(position a);
    std::vector<position> plus90(position a);      //basic moves
    std::vector<position> minus90(position a);
    std::vector<position> Lshape(position a);

    piece() : identify(non), pos(position(1,1)) {}
    virtual ~piece() {}
};

class Pawn : public piece{
public:
    Pawn() { identify = pawn; }
    std::vector<position> sovereign_movement() {std::vector<position> sol; return sol;}
    ~Pawn() = default;
};
[...]

#endif //PIECES_H

And my main for testing:

#include "pieces.h"

int main()
{
   piece a;
   vector<position> test = a.horizontal();
   for(unsigned int i=0; i<test.size() ;i++)
       {
        cout << test[i].Pconvert() << endl; /// position::Pconvert() just make string
       }
return 0;
}

I've a pieces.cpp file what define the longer methods:

#include "pieces.h"
#ifndef PIECES_H
#define PIECES_H

std::vector<position> piece::horizontal(position a){
    std::vector<position> sol;
    for(int i = 1;i<=8;i++){
        sol.push_back(position(i,a.y));
        if(i==a.x){sol.pop_back();}
    }
    return sol;
}

[...]

#endif //PIECES_H

For this I get undefined reference to piece::horizontal(position) and undefined reference to vtable for piece for constructor and destructor in header file.

If i do my destructor abstract (virtual ~piece() = 0) I get: error: cannot declare variable 'a' to be of abstract type 'piece', because the following functions are pure within 'piece': virtual piece::~piece()

After that I've write default destructors all of derived classes, but writes same. After this I modify my main this way (Pawn is one of derived classes of piece):

int main()
{
    piece* a = new Pawn();
    vector<position> test = a->horizontal(a->pos);
    for(unsigned int i=0;i<test.size();i++){
        cout << test[i].Pconvert() << endl;
    }
    return 0;
}

And then I get: undefined reference to 'piece::horizontal(position)' and undefined reference to piece's destructor in .h, so round is closed.

Could someone help me? Thank you

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • The line `#ifndef PIECES_H` in your header file is rather significant, but you left it out. (OK, I'm assuming it's in your header file, since that would explain why nothing in `pieces.cpp` was compiled.) – JaMiT Mar 18 '21 at 02:18
  • 1
    How are you compiling your project? Please show the exact compilation commands you're using. – Stephen Newell Mar 18 '21 at 02:34
  • If you are using VSCode did you modify your `tasks.json` to allow for compiling more than 1 source file since the default configuration supports building only the active file into an executable. If you are not please ignore the comment. The reason why I mention this is we see several dozen similar reports for VSCode each week. – drescherjm Mar 18 '21 at 02:40
  • @StephenNewell, I'm using codeblocks, and the default compiler of that. The only difference I made to switch on the C++11 in compiler settings. – Attila Szabó Mar 18 '21 at 02:56
  • @JaMiT Theres "anti-multipile" header guards in pieces.h and pieces.cpp too. – Attila Szabó Mar 18 '21 at 02:58
  • Get the header guards out of the .cpp file. Sorry I missed that last evening. I must have been tired. – drescherjm Mar 18 '21 at 13:44

1 Answers1

0

When you include a header file, the contents of that file replace the #include line. So when pieces.cpp starts like this:

#include "pieces.h"
#ifndef PIECES_H
#define PIECES_H

std::vector<position> piece::horizontal(position a){
    std::vector<position> sol;
    for(int i = 1;i<=8;i++){
        sol.push_back(position(i,a.y));
        if(i==a.x){sol.pop_back();}
    }
    return sol;
}

#endif //PIECES_H

it becomes the following after the pre-processor handles the #include.

#ifndef PIECES_H
#define PIECES_H
class piece{
public:
    bool dark; //0 = light, 1 = dark
    virtual std::vector<position> sovereign_movement();
    types identify; // enum types = {pawn, knight, king, etc...}
    position pos;
    std::vector<position> horizontal(position a);
    std::vector<position> vertical(position a);
    std::vector<position> plus90(position a);      //basic moves
    std::vector<position> minus90(position a);
    std::vector<position> Lshape(position a);

    piece() : identify(non), pos(position(1,1)) {}
    virtual ~piece() {}
};
#endif //PIECES_H
#ifndef PIECES_H
#define PIECES_H

std::vector<position> piece::horizontal(position a){
    std::vector<position> sol;
    for(int i = 1;i<=8;i++){
        sol.push_back(position(i,a.y));
        if(i==a.x){sol.pop_back();}
    }
    return sol;
}

#endif //PIECES_H

Next, account for the PIECES_H macro. I'll comment out the preprocessing lines as I proceed.

// #ifndef PIECES_H  -- PIECES_H is not defined yet, so proceed.
// #define PIECES_H  -- now PIECES_H is defined.
class piece{
public:
    bool dark; //0 = light, 1 = dark
    virtual std::vector<position> sovereign_movement();
    types identify; // enum types = {pawn, knight, king, etc...}
    position pos;
    std::vector<position> horizontal(position a);
    std::vector<position> vertical(position a);
    std::vector<position> plus90(position a);      //basic moves
    std::vector<position> minus90(position a);
    std::vector<position> Lshape(position a);

    piece() : identify(non), pos(position(1,1)) {}
    virtual ~piece() {}
};
// #endif //PIECES_H -- end of the earlier #ifndef
// #ifndef PIECES_H  -- PIECES_H is still defined from earlier. So skip ahead.
// All these lines are omitted from compilation
// #endif //PIECES_H -- end of the earlier #ifndef

The preprocessor just ripped out the contents of pieces.cpp because of the mis-use of header guards. Header guards belong in the header (see also A: C++ Header Guard Syntax and Header Placement). Take them out of your source file and it should compile as intended.

JaMiT
  • 14,422
  • 4
  • 15
  • 31