C++ Can't get files to compile?

Write your question here.

Not sure What I'm doing wrong, but I'm not really familiar with how linking works if that's the problem.

All files are in a folder called MyGame. I have a the compile error log at the bottom.


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
#include "Monsters.hpp"
#include "Player.hpp"
#include <iostream>
#include <string>



int main(){
    

    return 0;
}


ImpPlayer.cpp
1
2
3
4
5
6
7
8
9
10
11
#include "Player.hpp"
#include <iostream>
#include <string>

Player::Player(){
    name = "UnNamed";
    level = 1;
    exp = 0;
    health = 100;
    strength = 1;    
}


ImpMonsters.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "Monsters.hpp"
#include "Player.hpp"
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>

 Goblin::Goblin(){
    srand(time(NULL));
    name = "Goblin";
    level = (rand() % player.getLevel()) + 1;
    health = 100 * level - 50;
    strength = 1 + level; 
 }


Player.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#pragma once


class Player {
private:
    std::string name;
    int level;
    int exp;
    int health;
    int strength;
public:
    // Constructor
    Player();

    // Get values
    int getLevel()    { return level;    }
    int getExp()      { return exp;      }
    int getHealth()   { return health;   }
    int getStrength() { return strength; }

    // Set values
    void setLevel(int l)    { level = l;    }
    void setExp(int e)      { exp = e;      }
    void setHealth(int h)   { health = h;   }
    void setStrength(int s) { strength = s; }
}player;


Monsters.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pragma once


class Goblin {
private:
    std::string name;
    int level;
    int health;
    int strength;

public:

    Goblin();

     // Get values
    int getLevel()    { return level;    }
    int getHealth()   { return health;   }
    int getStrength() { return strength; }

    // Set values
    void setLevel(int l)    { level = l;    }
    void setHealth(int h)   { health = h;   }
    void setStrength(int s) { strength = s; }   

};



Compile log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
g++ -o play *.cpp
In file included from ImpMonsters.cpp:1:0:
Monsters.hpp:6:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string name;
          ^~~~~~
In file included from ImpMonsters.cpp:2:0:
Player.hpp:6:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string name;
          ^~~~~~
ImpMonsters.cpp: In constructor ‘Goblin::Goblin()’:
ImpMonsters.cpp:10:5: error: ‘name’ was not declared in this scope
     name = "Goblin";
     ^~~~
ImpMonsters.cpp:10:5: note: suggested alternative: ‘rename’
     name = "Goblin";
     ^~~~
     rename
In file included from ImpPlayer.cpp:1:0:
Player.hpp:6:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string name;
          ^~~~~~
ImpPlayer.cpp: In constructor ‘Player::Player()’:
ImpPlayer.cpp:6:5: error: ‘name’ was not declared in this scope
     name = "UnNamed";
     ^~~~
ImpPlayer.cpp:6:5: note: suggested alternative: ‘rename’
     name = "UnNamed";
     ^~~~
     rename
In file included from main.cpp:1:0:
Monsters.hpp:6:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string name;
          ^~~~~~
In file included from main.cpp:2:0:
Player.hpp:6:10: error: ‘string’ in namespace ‘std’ does not name a type
     std::string name;
          ^~~~~~
Check the order of your includes.

Monsters.hpp, for example, needs to know about <string>, but it is not yet included when that file is being processed.

Later in impmonsters.cpp you include <string>, but that's after the problem has already occurred.

Either include <string> in monsters.hpp, or include <string> before such "local application" includes.

You'll need to #include <string> in those header files as well if you want to use std::string in classes declared in those header files.

Unless you forward declare, but that comes with certain restrictions that I don't think you want here.

-Albatross
Try to use codeblocks, it makes most of the hassle go away. It works on linux and windows. Also eclipse but I dunno much about it.
Thanks everyone, I guess I need to watch some more videos on linking files. I'm not really to fond of code::blocks but I might try eclipse.
Any advice on my code so far?
It fixed a lot by adding the includes in the .hpp files but now I'm getting this. Not sure where I have multiple definitions of player. I created the object player at the end of the class in my Player.hpp and I used the player object in my ImpMonsters.cpp file.

1
2
3
4
5
/tmp/ccIM0qeG.o:(.bss+0x0): multiple definition of `player'
/tmp/ccV18AMU.o:(.bss+0x0): first defined here
/tmp/cchyCEAt.o:(.bss+0x0): multiple definition of `player'
/tmp/ccV18AMU.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
Sure, why not.

Goblin and Player feel like they should inherit from some base class. If you're into funny/poetic class names, how about "Murderer"?

You really shouldn't be creating variables like player in your header files. Remember that #include is a glorified copy-paste, meaning each source file that (indirectly or directly) includes it will wind up with a global named "player". What do you suppose will happen when the linker has to merge them?

Line 9 of ImplMonsters is going to shoot you in the foot the moment you try to make an array of goblins. srand(time(NULL)) should only be called once per program, not once per goblin. For that matter, we tend to recommend the C++11 <random> stuff over C's srand/rand. That might be something for you to research.

I don't see max health variables (or current health, depending on which one "health" is) anywhere. Are your entities not supposed to be able to heal up to a certain limit?

You might want to consider making your Goblin constructor take level as an argument, with the default being that random number formula.

A lot of your constructor code could be moved into initialization lists (not to be confused with initializer lists). https://www.cprogramming.com/tutorial/initialization-lists-c++.html

Setting the level does not recalculate the goblins' strength and health. Is that deliberate?

Take care,
-Albatross
Your input is very much appreciated, thanks. I'll work on the things you mentioned. I see now I made a lot of mistakes I need to correct. I realize there is no max health I was going to get around to it. This project is more of just a learning method for me then actually trying to make a text-based game, because I just wanna make sure I'm following good common practice for when I'm ready to make much more complex games.
I've been using <random> library as you suggested, but for the seed should I still use <ctime>?
For #include <files>
────────────────────
If you find yourself using std::string anywhere in your .cpp file, you should have #include <string> at the top. It does not matter whether the file is known to be included by some other header. If you use it, include it.


For IDE stuff
────────────────────
Find something you like and feel comfortable with. The IDE will not make all your problems go away (and would not have helped you here), but it does make life easier. Personally I like to use a good plain-text editor and compile everything at the command line.

If you do use an IDE, make sure to configure it to use the latest C++ standard when frobbing the compiler (C++17 if possible, C++11 at the absolute minimum).


For random stuff
────────────────────
The <chrono> library is a nice C++ wrapper over <ctime>.

If you click on the “Search” box at the top of the page you can type in “random” and the site search will typically bring up a good place to start reading. In this case, it brings up the page for the <random> library.

I scrolled down a little and chose the “ranlux24” generator and clicked it.
Then I clicked the link that says “(constructor)”, bringing me to this page:
    http://www.cplusplus.com/reference/random/discard_block_engine/discard_block_engine/
...which has a very convenient collection of examples for using the PRNG. The one most useful for you is:

1
2
3
4
5
6
7
8
9
10
11
#include <chrono>
#include <iostream>
#include <random>

int main()
{
  unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
  std::ranlux24 g4(seed);

  std::cout << "g4(): " << g4() << std::endl;
}

A PRNG is one of the few objects you should feel free to make a global. Hence:

1
2
#include <chrono>
#include <random> 
1
2
3
4
5
6
template <typename Integer>
Integer random( Integer min, Integer max )
{
  static std::ranlux24 rng( std::chrono::system_clock::now().time_since_epoch().count() );
  return std::uniform_int_distribution <int> ( min, max )( rng );
}
 
  level = random( 1, player.getLevel() );

Clicking on the “(constructor)” link in the documentation (both here and at cppreference.com) typically takes you to the best place to find example code.

Hope this helps.
Topic archived. No new replies allowed.