Multiple definition of class.

Hello,
I have a question about multiple definition of class LoaderException.

I have such code:

LevelLoader.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
27
28
#ifndef LEVELLOADER_HPP
#define LEVELLOADER_HPP

#include <vector>
#include <string>
#include <exception>
class Block;

namespace LevelLoader
{
    void LoadLevel(std::vector<Block>& container, std::string filepath);

        class LoaderException: public std::exception
        {
            virtual const char* what() const throw()
            {
                std::string returned = "Error: loading levelfile was not successfull.";
                return returned.c_str();
            }
        }LoaderException;

}

#endif //LEVELLOADER_HPP
//Format of a file:
//XPOS YPOS COLOR_INDEX
//XPOS YPOS COLOR_INDEX
//etc... 


LevelLoader.cpp
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
#include "LevelLoader.hpp"

#include <fstream>
#include "Block.hpp"
void LevelLoader::LoadLevel(std::vector<Block>& con, std::string filepath)
{
    std::ifstream file(filepath);
    if(file.is_open() )
    {
        while(file.good() )
        {
            int xpos;
            int ypos;
            int colorIndex;
            file >> xpos;
            file >> ypos;
            file >> colorIndex;
            con.push_back(Block(xpos, ypos, colorIndex));
        }
    }
    else

    {
        throw LoaderException;
    }
}


And it's not working. Debugger shows error:

obj/Debug/LevelLoader.o||In function `LevelLoader::LoadLevel(std::vector<Block, std::allocator<Block> >&, std::string)':|
/usr/include/c++/4.7/bits/vector.tcc|397|multiple definition of `LevelLoader::LoaderException'|

I found way around this, but I would like to know why it shows multiple declarations.

My solution is to declare this class in function body(void LoadLevel()), just before the throw statement. But why can't I define it inside my namespace, but outside function?
You're returning the address of a temporary
1
2
3
4
5
6
7
8
        class LoaderException: public std::exception
        {
            virtual const char* what() const throw()
            {
                std::string returned = "Error: loading levelfile was not successfull.";
                return returned.c_str();
            }
        };


It probably should be:
1
2
3
4
5
6
7
        class LoaderException: public std::runtime_error
        {
            LoaderException() :
                std::runtime_error("Error: loading levelfile was not successfull.")
            {
            }
        };
Last edited on
Look at line 20. That extra LoaderException after the closeing brace means you're not just defining the class, but actually instantiating a global object of that type within the namespace.

If you include this header file in more than one place, it means that the linker is seeing more than one attempt to create a global object with the same name. That's not legal.

Is there any particular reasion why you need your exception to be a global?
Last edited on
@kbw - I don't really know. It works fine the way it is, just class definition was forbidden there, and that's what I'm asking for. I'm using this pattern(so I just change class name and returned string) for few other objects, no complains and works as expected, but these were defined in other class body.

@Mikey - No. Okay, that explained it, I guess. So if I included LevelLoader.hpp in both LevelLoader.cpp and Level.hpp(some other header file), then it counts as creating this object twice, hence giving error?
So if I included LevelLoader.hpp in both LevelLoader.cpp and Level.hpp(some other header file), then it counts as creating this object twice, hence giving error?


Yes, exactly. It would be the same for any non-const global variable, regardless of type.

Having:

 
int myGlobalInt;

as a global variable in a header file would cause the same problem if the header were included in more than one file.

Note that, in C++, an exception is made for const globals. A const variable declared at namespace scope or global scope doesn't have external linkage - it's not truly global. You can safely put:

const int myGlobalConst = 17632;

in a header file and not cause linker problems. It's only non-const globals that cause problems in C++.

To be honest, you should use non-const globals as rarely as possible. They can cause all sorts of problems for your code.
And that's nice explanation. Thank you :)
You're welcome :)
Topic archived. No new replies allowed.