2

I have a problem, may be dumb.

The thing is, I am unable to inline a constructor in a class.

Consider I have a class called Foo.

If I write the implementation of Foo something like this:

class Foo {
  int p;
  public:
    Foo() { p = 1; }
};

or even like this:

class Foo {
  int p;
  public:
    Foo();
};

inline Foo::Foo() {
  p = 1;
}

The program won't compile.

I use the class using the standard method:

Foo obj;

Now when I run g++ main.cpp foo.cpp, I get:

/tmp/ccyVtxvp.o: In function `main':
main.cpp:(.text+0x17): undefined reference to `Foo::Foo()'
collect2: ld returned 1 exit status

At the same time, when I use the same code, after compiling the class as a shared library (with factory functions to return object pointer), it works properly.

Any guesses why this is happening?

Chubsdad
  • 24,777
  • 4
  • 73
  • 129
Nilesh
  • 624
  • 1
  • 7
  • 23
  • Is this a particularly old version of GCC, perhaps? – Andres Jaan Tack Nov 24 '10 at 12:57
  • 1
    Also, this looks like a linking error; are you certain that you're linking the object file into which Foo is written? – Andres Jaan Tack Nov 24 '10 at 12:59
  • what's in your `.h` header files? – Alex Brown Nov 24 '10 at 13:00
  • Are you having some namespaces and some 'Foo' in some namespace is not defining it's constructor? There is a chance of this happening if multiple namespace define Foo and you don't know which one you land up in using – Chubsdad Nov 24 '10 at 13:00
  • Use these options : -Wall -Wextra -ansi -pedantic – BЈовић Nov 24 '10 at 13:04
  • 1
    You say "like this", but what is the exact code you're using? Have you tried the exact examples above (and do they give the same error)? I wouldn't be surprised if this error is from a subtle difference between the actual code and the examples above. – Fred Nurk Nov 24 '10 at 13:06
  • @Fred, surprisingly that thing worked lol. I posted it without actually testing it. My bad. :( Anyways, the problem is solved now. Learned that you've to declare inline functions right in the file where you declare them. – Nilesh Nov 24 '10 at 13:16

7 Answers7

5

Inline functions must be defined in every source file in which they are used. The easiest way to achieve this is to put the definition(body) of the function in the header file and include the header wherever the function is used

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
1

Your program compiles, but doesn't link. Most likely you didn't include the object file containing the definition for the Foo class.

Or, if you defined it in a header, you just forward declared it, but didn't include the header.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • I did define a header foo.h, and have included that in main.cpp as well as foo.cpp. – Nilesh Nov 24 '10 at 13:01
  • @Nilesh, update this information in your post as it can mislead a lot – Chubsdad Nov 24 '10 at 13:03
  • 1
    I think the questioner's point is that an inline function should be inlined at compile time, and not generate a undefined symbol for the constructor's implementation. So "you forgot to link right" is not the right answer because the immediate response is "It's supposed to be *inlined*; there's not supposed to be anything to link!" – Mike DeSimone Nov 24 '10 at 13:05
  • 1
    @Mike inline is just a hint for the compiler. It has nothing to do with linking. – BЈовић Nov 24 '10 at 13:07
  • @Mike btw I followed the steps exactly as OP explained, and I didn't get the linker error. – BЈовић Nov 24 '10 at 13:10
  • I'm not buying that in the first example. Putting "inlined" code right in the class declaration is a technique that has been around as long as C++; there's no reason to expect the compiler to handle it wrong. And, yes, I also feel that the OP isn't including some key fact in the question. – Mike DeSimone Nov 24 '10 at 13:10
  • I will repeat : the error above is not from the compiler. It is a linker error. – BЈовић Nov 24 '10 at 13:13
0

You haven't mentioned what's in the header file and what's in the cpp.

To me this looks like you haven't actually compiled Foo::Foo. This can happen when you use inlines.

Alex Brown
  • 41,819
  • 10
  • 94
  • 108
0

My guess is that something is taking the address of Foo::Foo(). This will cause the compiler to expect a non-inlined version to exist somewhere.

Mike DeSimone
  • 41,631
  • 10
  • 72
  • 96
0

Here

inline Foo::Foo() {
     p = 1;
}

remove the inline. Add it in the declaration (in the header)

I'm not sure why this works, but works. I've had the same problem and this solved it.


EDIT: something like this:


class Foo {
  int p;
  public:
  //vvvvvv
    inline Foo();
};

Foo::Foo() {
  p = 1;
}
Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
0

The problem is this one:

/tmp/ccyVtxvp.o: In function main': main.cpp:(.text+0x17): undefined reference toFoo::Foo()' collect2: ld returned 1 exit status

I infer that you have the class defined in foo.cpp, and you're trying to use it in main.cpp. As others have said, C++ don't know how to use Foo, or even its existence, if you don't declare it previously. Module management in C++ is quite complex, and primitive. You're maybe biased by other more modern programming languages such as C# or Java.

Create foo.h:

// foo.h
class Foo:
int p;
public:
    Foo() { p = 1; }
};

All the methods you define in the class declaration are automatically considered inline. As a dumb rule, you should create a .cpp file (foo.cpp) matching each declaration or interface file (foo.h). In this case, it is fruitless, since your complete class lies in the interface file. Bur probably your class will grow in complexity, and eventually you'll need to have a method definition in your cpp. So:

Create foo.cpp:

// foo.cpp
#include "foo.h"

Now, in main.cpp you can use Foo, by including its declaration. This is mandatory in C++:

Create main.cpp:

// main.cpp

#include "foo.h"

#include <cstdlib>
#include <cstdio>

int main()
{
    Foo f;
    std::printf( "Foo was created\n" );

    return EXIT_SUCCESS;
}
Baltasarq
  • 12,014
  • 3
  • 38
  • 57
  • 1
    If `class Foo` wasn't defined by the time `main.cpp` tried to create a `Foo`, wouldn't that fail at *compile* time? – Mike DeSimone Nov 24 '10 at 13:14
  • Defined and declared have different meanings in C++. What you put in a .h file is normally a declaration (it can sometimes include definitions, such as inline methods), while what you put in a cpp file is normally a definition. When you create Foo in main(), Foo must be declared, not necessarily defined. When the linker processes all pending links, then it must be completely defined. – Baltasarq Nov 24 '10 at 13:18
0

I) When directly building the object, the compiler tries to minimize the work and the object size. Here are the steps the compiler takes:

1) Compile main.cpp. Encounters a call to Foo. At this time, compiler JUST checks the declaration of Foo. The declaration is not inline, hence it adds a function call to Foo in the code.

2) Compiles file.cpp (file containing your class definition). Note that inline functions are NOT compiled (rightly so). They are just expanded to code wherever the function is called (provided the definition is available in that file).

3) Now, when it tries to link, it does not find the definition of Foo.

II) When building as a library, compiler will compile all associated functions. (you can very well guess why). Hence the linking goes through.


I am sure you know how to solve the problem yourself:

class Foo {
  int p;
  public:
    inline Foo() { p = 1; };
};

but assume you were just wondering why the different behaviour in direct object creation vs building a library.