0

I wrote a simple class which manages the current execution session. Therefore, I decided to use a singleton pattern but the compilation crashes at linked step. This is the error:

error LNK2005: "class Session * session" (?session@@3PAVSession@@A) already defined in ClientTsFrm.obj
(...)client\FrmSaveChat.obj TeamTranslate
error LNK2005: "class Session * session" (?session@@3PAVSession@@A) already defined in ClientTsFrm.obj
(...)client\Login.obj TeamTranslate
error LNK2019: unresolved external symbol "protected: __thiscall Session::Session(void)" (??0Session@@IAE@XZ)
  referenced in function "public: static class Session * __cdecl Session::Instance(void)" (?Instance@Session@@SAPAV1@XZ)
(...)client\Session.obj TeamTranslate
error LNK2001: unresolved external symbol "private: static char const * const Session::_nick" (?_nick@Session@@0PBDB)
(...)client\Session.obj TeamTranslate
error LNK2001: unresolved external symbol "private: static char const * const Session::_service" (?_service@Session@@0PBDB)
(...)client\Session.obj TeamTranslate
error LNK2001: unresolved external symbol "private: static char const * const Session::_serverAddress" (?_serverAddress@Session@@0PBDB)
(...)client\Session.obj TeamTranslate
error LNK2001: unresolved external symbol "private: static char const * const Session::_googleAPI" (?_googleAPI@Session@@0PBDB)
(...)client\Session.obj TeamTranslate
error LNK2001: unresolved external symbol "private: static char const * const Session::_language" (?_language@Session@@0PBDB)
(...)client\Session.obj TeamTranslate
error LNK2001: unresolved external symbol "private: static int Session::_numbLanguageSelected" (?_numbLanguageSelected@Session@@0HA)
(...)client\Session.obj TeamTranslate
error LNK2001: unresolved external symbol "private: static char const * const Session::_translationEngine" (?_translationEngine@Session@@0PBDB)
(...)client\Session.obj TeamTranslate
error LNK1120: 8 unresolved externals
(...)client\bin\TeamTranslate.exe TeamTranslate
IntelliSense: identifier "wxZipStreamLink" is undefined
(..)\include\wx\zipstrm.h 417 5

session.h (singleton)

#ifndef __SESSION_H__
#define __SESSION_H__

#include <cstring>
#include <stdio.h>

class Session {
public:
    static Session* Instance();

    void setNick(char* nick);
    const char* getNick();

    void setService(char* serv);
    const char* getService();

    void setLanguage(char* lang);
    const char* getLanguage();

    const char* getServerAddress();
    void setServerAddress(char *sv);

    void setGoogleAPIKey(char* code);
    const char* getGoogleAPIKey();

    void setNumbLanguageSelected(int v);
    int getNumbLanguageSelected();

    const char* Session::getTranslationEngine();
    void Session::setTranslationEngine(char *sv);

    char* Session::getGoogleURLTranslation();

    void update();
    bool read();
protected:
    Session();
private:
    static Session* _instance;
    static const char* _nick; //  client nickname
    static const char* _service; // service used to translation (Google, Bing,....)
    static const char* _serverAddress;
    static const char* _googleAPI;
    static const char* _language;
    static int _numbLanguageSelected;
    static const char* _translationEngine;
};

#endif

Session.cpp

#include "Session.h"

Session* Session::_instance = 0;

Session* Session::Instance() {
    if (_instance == 0) {
        _instance = new Session;
        _instance->read();
    }
    return _instance;
}

void Session::setGoogleAPIKey(char* code){
    _googleAPI = strdup(code);
}

const char* Session::getGoogleAPIKey(){
    return _googleAPI;
}

void Session::setLanguage(char* lang){
    _language = strdup(lang);
}

const char* Session::getLanguage(){
    return _language;
}

void Session::setNick(char* nick){
    _nick = strdup(nick);
}

const char* Session::getNick(){
    return _nick;
}

void Session::setService(char* serv){
    _service = strdup(serv);
}

const char* Session::getService(){
    return _service;
}

const char* Session::getServerAddress(){
    return _serverAddress;
}

void Session::setServerAddress(char *sv){
    _serverAddress = strdup(sv);
}

void Session::setNumbLanguageSelected(int v){
    this->_numbLanguageSelected = v;
}
int Session::getNumbLanguageSelected(){
    return _numbLanguageSelected;
}

const char* Session::getTranslationEngine(){
    return _translationEngine;
}

void Session::setTranslationEngine(char* sv){
    _translationEngine = strdup(sv);
}


void Session::update(){
    FILE* config = fopen("conf\\config.txt", "w");
    fprintf(config, "%s\n", _serverAddress);
    fprintf(config, "%s\n", _nick);
    fprintf(config, "%d\n", _numbLanguageSelected);
    fprintf(config, "%s\n", _language);
    fprintf(config, "%s", _translationEngine);
    fflush(config);
    fclose(config);
}

bool Session::read(){
    FILE * config;
    if (config = fopen("conf\\config.txt", "r"))
    {
        fscanf(config, "%s", _serverAddress);
        fscanf(config, "%s", _nick);
        fscanf(config, "%d", _numbLanguageSelected);
        fscanf(config, "%s", _language);
        fscanf(config, "%s", _translationEngine);
        fflush(config);
        fclose(config);
        return true;
    } else
        return false;
}


 char* Session::getGoogleURLTranslation(){
    return "https://www.googleapis.com/language/translate/v2?key=";
}

Example about how I call the singleton:

#include "../data/Session.h"

static Session* session = Session::Instance();

Can you help me to fix the errors?

thanks in advance.

Oktalist
  • 14,336
  • 3
  • 43
  • 63
Daniel 976034
  • 189
  • 1
  • 1
  • 18
  • Just an FYI, a `protected` constructor does not guarantee one instance of the class, as any number of subclasses could also create an instance. For a real singleton, you should have a `private` constructor. – clcto Feb 13 '15 at 15:19
  • Don't you mean `_instance = new Session()` instead of `_instance = new Session` ? in the Instance() function ? – Thomas Benard Feb 13 '15 at 15:20
  • 3
    This is a very weird mix. Why do you have static members, but instance level get/set methods? Why do your set methods take non-const data? Where do you free what you _strdup'ed? Why are your getters non-const? – nvoigt Feb 13 '15 at 15:20
  • 1
    And another [illegal include-guard](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier)! – Baum mit Augen Feb 13 '15 at 15:20
  • First error tells you you've redefined the session pointer; second error tells you that you can't access the _nick member; getNick and setNick either need to access Session::_nick, or should be static themselves. – Mike P Feb 13 '15 at 15:22
  • 1
    @ThomasBenard: That won't make any difference. The class has a default constructor, so default- and value-initialisation both do exactly the same thing. – Mike Seymour Feb 13 '15 at 15:25
  • @clcto I taked the singleton pattern from the book "Design Patterns. Elements of Reusable Object-Oriented Software". And it said: "Notice that the constructor is protected. A client that tries to instantiate Singleton directly will get an error at compile-time. This ensures that only one instance can ever get created". – Daniel 976034 Feb 13 '15 at 15:25
  • @BaummitAugen Could you be more specific?? Thanks! – Daniel 976034 Feb 13 '15 at 15:27
  • 4
    Well your book is wrong. You can create a `class SubSingleton : public Singleton { public: SubSingleton() {} };` and now you can create as many as you want. – clcto Feb 13 '15 at 15:27
  • 1
    @Daniel976034 As stated on the page I linked (did you click on that?), `__SESSION_H__` is an implementation reserved name. – Baum mit Augen Feb 13 '15 at 15:29
  • @nvoigt Please, do you mind to explain why is a weird mix? I chose "const" because the value doesn't change, was it a bad idea in this context? Thanks in advance. – Daniel 976034 Feb 13 '15 at 15:42
  • 1
    Given that you are using C++, it's rather confusing that your code is written as if it was C with classes... C++ is not C with classes. At the very least, you could use `std::vector` or `std::string` for your strings. – Kuba hasn't forgotten Monica Feb 13 '15 at 17:18

1 Answers1

1

One of your headers (which you didn't show, but it is included in both "ClientTsFrm.cpp" and "FrmSaveChat.cpp") defines a variable called "session" of type Session*.

The other errors are caused by your forgetting to define most static members of Session.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82