7

my_test.h

#ifndef MY_TEST  
#define MY_TEST

struct obj {
  int x;
  int y;
};

class A {
private:
  const static int a=100;
  const static obj b;
};

const obj A::b={1,2};

#endif

When compiling cpp using this header file, an error 'multiple definition of 'A::b' occurs.

  1. why is this when I have been using guard macro already?
  2. why does A::a not produce the erro? (I can't write code const static obj b={1,2} in class A)
Carl Suster
  • 5,826
  • 2
  • 22
  • 36
Shawn
  • 1,441
  • 4
  • 22
  • 36

4 Answers4

4

why is this when I have been using guard macro already?

Header guards only prevent the inclusion of the header file contents more than once in the same translation unit not across multiple translation units.

why is A::a does not have the error message (I can't write code const static obj b={1,2} in class A)

In-class initialization is allowed by the compiler as a special case for static data members of const literal type. Your example one is In-class initialization.

const A::b defines the same symbol name in each translation unit where the header gets included and hence breaks the one definition rule.

You need to move the definition to one and only one source cpp file so that it gets defined only once.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 2
    For the OP, as a beginner, the "You need to" is correct. However, as an absolute technical statement it's not, because there is an ODR excemption for class templates. Which means that technically, if there is real need for it, one can define the static constant in a class template and then inherit from an arbitrary specialization. It's sometimes known as the templated constant trick. A more practical way to avoid an implementation file, if one does, is to provide access to the constant via an inline function (which can have the constant as a local).' – Cheers and hth. - Alf Feb 22 '13 at 10:07
  • @Alf: I agree to what your comment says. In fact that is a good piece of information. – Alok Save Feb 22 '13 at 13:55
1

Alok has already answered your question, but here are a few simple rules of thumb, in easy-to-memorize form:

  1. Declarations go in the .h file
  2. Definitions go in the .cpp file

Therefore, static members need to be declared in the .h file, and then defined in the .cpp file. In your case, fix the syntax for the declarations and then move them to "my_test.cpp" file.

Rahul Banerjee
  • 2,343
  • 15
  • 16
0

The problem is your definition of A::b doesn't contain a type. To be a valid definition, it should be:

const obj A::b = {1, 2};

This will get rid of the compilation error, but you'll still get linker errors if you include this header in more than one source file, because A::b will be multiply defined then. You should move the definition into a .cpp file.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
0

Regardless of whether you have a header guard or not, placing that initialisation in a header file will mean you'll get an instance of A::b in every source file that includes that header file. Hence the linker error.

So, generally speaking, it's possible, but not a good idea.