1

I am writing a new REST router for an application. It has some old C++ classes called Route and so forth. I've created some new classes, namely (you guessed it) Route and RouteManager. There are literally 0 namespaces used in this entire application. So I figured by introducing my own namespace (WebRouter) I could code while keeping the old code in the project.

Obviously this didn't work. My compiler (C++98) is complaining about things that are already defined (Route and the cout overload). This is how I tried to accomplish my goal of keeping the old Route class while namespacing a new Route class.

Route.hpp

namespace WebRouter {
    // complains this is defined, which it is for the old Route..
    class Route {
        private:
        protected:
        public:
            string uri;
            string method;
            Route(string uri, string method);
            ~Route();
    };
}
// complains this is already defined, which it is for the old Route..
ostream &operator<<(std::ostream &os, WebRouter::Route const &route) { 
    os << "--- Route ---" << endl;
    os << "- URI: " << route.uri << endl;
    os << "- Method: " << route.method << endl;
    os << "-------------" << endl;
    return os;
}

Route.cpp

#include "Route.hpp"
using namespace WebRouter;

Route::Route(string uri, string method){
    this->uri = uri;
    this->method = method;
}
Route::~Route(){}

RouteManager.hpp

namespace WebRouter {
    class RouteManager {
        private:
            vector<Route> RouteVector;
        protected:
        public:
            RouteManager();
            ~RouteManager();
            Route* FindRoute(string uri, string method);
    };
}

RouteManager.cpp

#include "RouterManager.hpp"
using namespace WebRouter;

RouteManager::RouteManager() {}
RouteManager::~RouteManager() {}

The specific error is

multiple definition of 'global constructors keyed to 2343_2__zoidfiosdiof**WebRouter**5**Route**E'

This happens whether I do using or prefix with WebRouter::

J Doe.
  • 299
  • 3
  • 13
  • 6
    `using namespace WebRouter;` well that's your problem right here. – n. m. could be an AI Feb 06 '18 at 19:27
  • 1
    just dont be lazy. The `using` will just make you have a `Router` and a `Router` that are actually two differnt things. Isnt `Router` vs `WebRouter::Router` much easier to distinguish? – 463035818_is_not_an_ai Feb 06 '18 at 19:29
  • What happens if you get rid of `using namespace WebRouter` and instead prefix your functions in `RouteManager.cpp` with `WebRouter::`? – 01010011 01000010 Feb 06 '18 at 19:30
  • Sorry friends but removing the `using` and prefixing with `WebRouter::` does not accomplish anything. It still complains to me `multiple definition of 'global constructors keyed to (gibberish text)WebRouter Route` – J Doe. Feb 06 '18 at 19:33
  • @JDoe.: You have to remove `using WebRouter;` from _all_ header files, not just this one – Mooing Duck Feb 06 '18 at 19:38
  • 2
    The idiomatic way would be to just declare the namespace in the CPP file again, like `namespace WebRouter{ Route::Route(...){} Route::~Route(){} }`. – zett42 Feb 06 '18 at 19:38

1 Answers1

1

Several things should or must be changed (we don't have all your source files to check that):

  1. Don't use using namespace WebRouter, as several comments state it's a better policy to use WebRouter::
  2. Your Route constructor and destructor definitions should also go inside of the WebRouter namespace in the cpp file.
  3. The output stream overload for the Route class can also go inside of the class scope as friend and defined inside of the namespace.
FrankS101
  • 2,112
  • 6
  • 26
  • 40
  • Well after removing the overload, everything compiles fine (even as per my original code). However if I put the overload within the `WebRouter` namespace in the `Route.hpp` file, it is still the only thing it's complaining about... – J Doe. Feb 06 '18 at 19:49
  • have you declared the function as `friend ostream &operator<<(std::ostream &os, WebRouter::Route const &route);` inside of the Route class? – FrankS101 Feb 06 '18 at 19:51
  • Yes. All this would do is give me access to private variables. It still thinks it's been defined twice. At this point it doesn't even look like it has anything to do with the old classes. – J Doe. Feb 06 '18 at 19:55
  • Yep definitely something fishy going on. I renamed it to `Route2` and same problems =/ – J Doe. Feb 06 '18 at 20:06
  • If the overload of the output operator for the WebRouter::Route class is defined inside of the namespace, there is no reason to be double defined. Something else might be wrong. – FrankS101 Feb 06 '18 at 20:09
  • 1
    It is definitely being double defined. `RouteManager.hpp` includes `Route.hpp` and `Route.cpp` includes `Route.hpp`. Thus the operator was double defined. I moved the entire thing into the class header and now it works. Lesson learned. see [this answer](https://stackoverflow.com/questions/12802536/c-multiple-definitions-of-operator) . Also maybe that's what your 3rd point meant, but I didn't understand. – J Doe. Feb 06 '18 at 20:11
  • @JDoe. Then, definitely yes, it was double defined. – FrankS101 Feb 06 '18 at 20:15