6

I have a C++ classe in a .h file like this:

#ifndef __GLWidget_h__
#define __GLWidget_h__

class PivotShape
{
    // This is allowed
    void do_something() { std::cout << "Doing something\n"; }

    // This is not allowed
    void do_something_else();
}

// This is not allowed
void PivotShape::do_something_else()
{
    std::cout << "Doing something else\n";
}

#endif

If I add methods inside the class declaration everything seems fine. But if I add methods outside of the class declaration, I get errors like this:

/usr/share/qt4/bin/moc GLWidget.h > GLWidget_moc.cpp
/programs/gcc-4.6.3/installation/bin/g++ -W -Wall -g -c -I./ -I/usr/include/qt4 GLWidget_moc.cpp
/programs/gcc-4.6.3/installation/bin/g++ main.o GLState.o GLWidget.o MainWindow_moc.o GLWidget_moc.o -L/usr/lib/x86_64-linux-gnu -lQtGui -lQtOpenGL -lQtCore -lGLU -lGL -lm -ldl -o main
GLWidget.o: In function `std::iterator_traits<float const*>::iterator_category std::__iterator_category<float const*>(float const* const&)':
/home/<user>/<dir>/<dir>/<dir>/<dir>/<dir>/GLWidget.h:141: multiple definition of `PivotShape::do_someting_else()'
main.o:/home/<user>/<dir>/<dir>/<dir>/<dir>/<dir>/GLWidget.h:141: first defined here

I think the duplication is being caused by this snippet in the Make file. I think the .h files are being converted to _moc.cpp files and this is allowing the multiple inclusions:

# Define linker
LINKER        = /programs/gcc-4.6.3/installation/bin/g++

MOCSRCS       = $(QTHEADERS:.h=_moc.cpp)

# Define all object files to be the same as CPPSRCS but with all the .cpp
# suffixes replaced with .o
OBJ           = $(CPPSRCS:.cpp=.o) $(MOCSRCS:.cpp=.o)

Is this the problem? If so, how can I fix it? If not, what's going on?

I thought it was illegal in C++ to include class methods inside the body of the class declaration. If this is legal, then it seems like an easy way to solve the problem. Is this legal?

Edit:

I forgot to mention that I had already discovered that declaring the methods as inline works, but I was wondering how to avoid the duplication.

Schemer
  • 1,635
  • 4
  • 19
  • 39

2 Answers2

15

You're breaking the One Definition Rule; defining the function in the header means there's a definition in every translation unit that includes the header, and you're usually only allowed a single definition in the program.

Options:

  • Move the function definition into a source file, so there's just one definition; or
  • Add inline to the function definition, to relax the rule and allow multiple definitions; or
  • Define the function inside the class, which makes it implicitly inline. (To answer your final question, yes that is legal.)

Also, don't use reserved names like __GLWidget_h__.

Community
  • 1
  • 1
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Thanks. So what's happening is that A.cpp and B.cpp are both including the .h file, resulting in multiple definitions? No single .cpp file could have multiple inclusions due to the `#ifndef...#endif` statements. But wouldn't that mean that all class definitions in .h files are repeated? Are they implicitly `inline` -- and this is why functions inside the class are implicitly `inline`? – Schemer Feb 10 '15 at 12:05
  • 2
    @Schemer: Yes, you get a definition in each translation unit (where a translation unit corresponds to a source file and everything it includes). The include guards prevent multiple definitions within each unit, but don't stop definitions in other units. Class definitions, inline functions, templates, and various other things, can be defined in more than one unit, as long as the definitions are identical. Non-inline functions and variables can only be defined once. – Mike Seymour Feb 10 '15 at 13:26
  • 1
    To expand on what Mike is saying: the rule is "Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required" The "no diagnostic required" means that anything else is undefined behavior, even though in practice, all of the compilers I know will signal an error for multiple definitions (and missing definitions). – James Kanze Feb 10 '15 at 14:20
  • So, it seems there is some unavoidable code duplication. When I was trying to diagnose the problem, I thought this must _not_ be the case so I ruled it out. Thanks to all for the helpful comments! – Schemer Feb 10 '15 at 17:43
  • I wonder why then such code works when you declare/implement template methods that way? – Alexey Apr 03 '20 at 10:01
2

Define the function in a source file or use inline to define it in the header file, outside the class definition.

Note that you can still define it inside the class definition without the inline keyword.

Related: Member function definition

Community
  • 1
  • 1
Emil Laine
  • 41,598
  • 9
  • 101
  • 157