-4

I'm working through an intro video series on cpp and I'm running into a linker error, but I'm not sure why I'm hitting it.

the error

I'm def still green to reading complier and linker errors so this may be wrong, but it seems like the linker is telling me that I haven't defined the methods that I'm calling in my main function. It makes me suspect that I have something wrong in my header file. Here's the current state of my files:

main.cpp

#include "Log.h"

int main() {

    Log log;

    log.SetLevel(Log::LevelError);
    log.Warn("hello from main");
    log.Error("hello from main");
    log.Info("hello from main");
}

Log.h

#pragma once

class Log {
public: // variables
    enum Level {
        LevelError, LevelWarning, LevelInfo
    };
public: // methods
    void SetLevel(Level level);
    void Error(const char* message);
    void Warn(const char* message);
    void Info(const char* message);
};

Log.cpp

#include <iostream>

class Log {
public: // variables
    enum Level {
        LevelError, LevelWarning, LevelInfo
    };

private: // variables
    Level m_LogLevel = LevelWarning;

public: // methods
    void SetLevel(Level level){
        m_LogLevel = level;
    }

    void Error(const char* message){
        if (m_LogLevel >= LevelError)
            std::cout << "[ERROR]: " << message << std::endl;
    }
    void Warn(const char* message){
        if (m_LogLevel >= LevelWarning)
            std::cout << "[WARNING]: " << message << std::endl;
    }
    void Info(const char* message){
        if (m_LogLevel >= LevelInfo)
            std::cout << "[Info]: " << message << std::endl;
    }
};

In the video series I'm watching the instructor defined the log class within the main.cpp file, but I wanted to try to start organizing my files by moving the log class out to it's own file and pulling it in via a header file.

I tried to figure out what I'm doing wrong by searching around on the internet, but whether it's because I can't find the exact problem I'm hitting or I'm just still to green to cpp to see the solution in the answers I'm finding I can't seem to figure it out.

Can someone point me in the right direction, please??

Chris Schmitz
  • 20,160
  • 30
  • 81
  • 137
  • Add `#include "Log.h"` into Log.cpp – Dmytro Prylipko Jan 23 '19 at 14:52
  • @matthieu-brucher I'm reading through this answer and mine may be a duplicate, but one of the issues I mentioned is that I have been searching through and reading possible solutions but I don't really understand what I'm reading in relation to the issue I'm hitting now. These answers are def informative, but I've said I'm already running into problems scaling the walls of information I'm finding. In the end, even if I read through all of these answers, but I still can't figure out how it applies to my situation they're not really helpful. – Chris Schmitz Jan 23 '19 at 14:52
  • @matthieu-brucher you glanced at my question and closed it without actually reading it. The problem that I'm running into isn't just the error I'm getting, it's that I can't seem to figure out what within the wall of text I've found already and that you've pointed me to actually applies to my problem. You're closing my question b/c you're not seeing the forest from the trees. – Chris Schmitz Jan 23 '19 at 14:56
  • @DmytroPrylipko I tried adding an include for the log header file into my Log.cpp file and I get a `Redefinition of 'Log'` error. Is my declaration in the header file wrong? – Chris Schmitz Jan 23 '19 at 14:57
  • 5
    Wait a second, why do you define the class again in the .cpp? The content of the .cpp file must be like `void Log::Error(const char* message)`, but instead you define the class again, now with implementation. See this: https://stackoverflow.com/questions/9579930/separating-class-code-into-a-header-and-cpp-file – Dmytro Prylipko Jan 23 '19 at 15:01
  • You're right, I am trying something I didn't learn yet. I was trying to expand a bit past what I'd been learning already to see if I could figure it out, and I was almost there but was stuck. I did get a helpful point that did get me unstuck, and it didn't require cutting me down for trying to learn. It's disappointing that a newbie asking for help on what is a simple error for you and other experienced devs is met with negativity from more experienced developers. What good are you doing for making me feel bad for being new to cpp?? – Chris Schmitz Jan 23 '19 at 15:48
  • Yeah dude, I _did read the documentation_ and while I understood some of it _I didn't understand how it applied to my specific issue_. Look at my answer to the question, I was close, I understood what was once I got a point in the right direction. Saying "read the documentation" as a stack overflow reply is a cop out because it assumes that the person didn't already try and also assumes that all documentation is written in a way that is clear to everyone and always yields epiphanies to every issue. Sometimes when you're new to something the documentation alone isn't the best answer. – Chris Schmitz Jan 23 '19 at 15:54

1 Answers1

-1

Thanks @DmytroPrylipko for the point int the right direction via the link to the stackoverflow question and answer: Separating class code into a header and cpp file

After reading your comments and then looking for the answer it helped me realize that my hang up was from my Log.cpp not including the Log.h file I had defined and then the contents of my Log.cpp file re-defining the class.

For anyone else who may run into this kind of issue, here's how I fixed my code.

My main.cpp file stayed the same:

#include <iostream>
#include "Log.h"

int main() {

    Log log;

    log.SetLevel(Log::LevelError);
    log.Warn("hello from main");
    log.Error("hello from main");
    log.Info("hello from main");
}

But I altered my Log.h file to include the private property in the base class definition:

#pragma once

class Log {
public: // variables
    enum Level {
        LevelError, LevelWarning, LevelInfo
    };
private: // variables 
    Level m_LogLevel = LevelWarning;
public: // methods
    void SetLevel(Level level);
    void Error(const char* message);
    void Warn(const char* message);
    void Info(const char* message);
};

The part that hung me up conceptually was the new structure of Log.cpp. As Dmytro suggested, I added an include for the Log.h file into my Log.cpp file, but I forgot that this is a pre-processor statement that essentially copy/pastes the code from Log.h into Log.cpp, so the re-declaration error I was getting was because I was defining class Log ... twice in the object file; once from the header and once from the Log.cpp.

Knowing that and seeing the syntax for adding methods to an existing class definition from the linked SO post, I updated my Log.cpp file to look like this:

#include <iostream>
#include "Log.h"


void Log::SetLevel(Level level){
    m_LogLevel = level;
}

void Log::Error(const char* message){
    if (m_LogLevel >= LevelError)
        std::cout << "[ERROR]: " << message << std::endl;
}
void Log::Warn(const char* message){
    if (m_LogLevel >= LevelWarning)
        std::cout << "[WARNING]: " << message << std::endl;
}
void Log::Info(const char* message){
    if (m_LogLevel >= LevelInfo)
        std::cout << "[Info]: " << message << std::endl;
}

So now my header file defines the class and the cpp file adds methods to it. In the tutorials I'm following I hadn't gotten to this syntax yet and I wasn't quite understanding documentation I was reading that has a lot of assumptions on what I already knew about cpp.

Thanks again for the point. I'm unstuck now and and have a bit of a taste, for better and worse, of what the cpp community is like.

Chris Schmitz
  • 20,160
  • 30
  • 81
  • 137