-2

I'm basically having header issues.

#include "Base.h"
class Factory
{
    public:
        static Base generateReply(int input);
};

And then the factory cxx file

#include "derived1.h"
#include "Factory.h"
Base Factory::generateReply(int input)
switch(input)
{
    case(0):
      return Base();
    case(1):
      return derived1();
    .....
}

And then I have the base class header file

class Base
{
   protected:
       std::string type;
   public:
       Base(){};
       Base(std::string in);
       virtual std::string doStuff();
}

Along with it's cxx file

#include "Base.h"
Base::Base(std::string in)
{
    type = in;
}

and then the derived one class

#include "Base.h"
class derived1: public Base
{
    public:
       derived1();
       derived1(std::string in) : Base(in){};
       std::string doStuff();
}

followed by the cxx file for it

#include "derived1.h"

std::string derived1::doStuff()
{
  return type;
}

Now each individual component compiles just fine. It's when I try to link everything together that everything goes all wrong. I get things such as

derived1.cxx:20: undefined reference to `Base::helper1(unsigned char) Where helper1 is a protected method that does exist(in my code) in Base

Or even

derived1.cxx:28: undefined reference to `derived1::helper2(unsigned char, unsigned char) Where helper2 is a private method for derived that does exist in my code. Which is weird since derived1 compiled just fine. You would think it would have thrown an error for finding it's helper2 method during compilation?

Or if I mess around with my includes I will get

error: could not convert ‘SenseType' from ‘SenseType’ to ‘Response’

I know it's my includes that are messed up, or maybe I just am completely incapable of even doing a factory pattern. All the examples online make it look like I did it right, they just never have the includes(s) included. I'm guessing it's

I do have guards for all of my header files. Also, if it's of any help, all of the linker errors are in the derived class.

JoeManiaci
  • 435
  • 3
  • 15
  • 1
    `Base::helper1` is not in your code. Neither is helper 2, nor SenseType, nor Response. – deviantfan Aug 16 '16 at 19:54
  • I didn't put them in the above portion to keep it as simple as possible, hence why I wrote it is a protected method. It is in my actual code. – JoeManiaci Aug 16 '16 at 19:55
  • 1
    Well, but apparently there is a code problem with helper2, and it's not the `protected` keyword. – deviantfan Aug 16 '16 at 19:56
  • 1
    Btw., missing includes (for your case) or missing include guards can't cause "missing" linker errors. The problem is a different one. – deviantfan Aug 16 '16 at 19:57
  • 3
    Try to prepare [MCVE](http://stackoverflow.com/help/mcve)... This actually can help you find the problem and maybe you won't even have to ask question here... – W.F. Aug 16 '16 at 19:59
  • That's what I thought, so I tested it by compiling just the derived and it compiled just fine. Wouldn't it complain about not finding a valid method signature for it's own private method then? Instead of during linkage? – JoeManiaci Aug 16 '16 at 20:00
  • @JoeManiaci: No. Functions need to be declared in order to compile, and defined in order to link. A function that isn't defined will compile, but not link. – Mooing Duck Aug 16 '16 at 20:31

3 Answers3

0

So I am answering my own question for anyone else that makes the same stupid mistake.

So for the error message at the bottom

derived1.cxx:20: undefined reference to `Base::helper1(unsigned char)

I did not have void Base::helper1() in the cxx file, I had void helper1()

I still don't get why it didn't catch it during compilation? Why did it not show the error until the linkage?

JoeManiaci
  • 435
  • 3
  • 15
  • 2
    `void helper1()` is a valid function, and `Base::helper1` can be defined in literally any file. The compiler can't know it's missing because the compiler only sees one cpp file at a time. The linker combines the compiler outputs, and the linker sees that the `Base::helper1` isn't in any of them. – Mooing Duck Aug 16 '16 at 20:32
0

For the question you asked in your own answer, I believe that because you didn't scope in your function using Base:: that it was treating it as a global function, and therefore didn't complain until it tried to link the files. I've run into this issue before, and from then on I had to make a habit of always scoping in any functions contained within the .cpp file. I hope this helps.

RichardJones
  • 149
  • 1
  • 10
0

It's hard to say without a bigger picture of what your situation is, but my guess is that your code was compiling because it was still valid within each compilation unit (each individual cpp/cxx file).

C++ will allow you to declare something but not define it, and it will compile just fine. As long as nothing references the thing that was undefined, there will be no errors in compiling or even linking.

However, if you try to reference something that was not defined, you will get linker errors.

Example: (Test.h)

class Test
{
public:
    int methodA();
    int methodB();
};

Now in Test.cpp

    #include "Test.h"
    int Test::methodA() { return 42; }

In this case, the compilation unit "Test.cpp" will compile just fine. However, if we then have a Main.cpp as follows...

#include "Test.h"
void main()
{
    Test test;
    test.methodA(); // Works fine...
    // test.methodB() <-- Causes linker error if uncomented.    
}

So you can easily get situations where all files can "compile" on their own, but run into errors during linkage.

Edit to address your other question. If there is, it would be compiler specific. I don't know about VisualStudio, but I believe that GCC has such a flag. See Force GCC to notify about undefined references in shared libraries

Community
  • 1
  • 1
Meta
  • 121
  • 6
  • Is there a flag you can use during compilation to warn if you declared a method in your .h file, but didn't define it in your cpp file? – JoeManiaci Aug 17 '16 at 15:24