Question

I have a templated class Child which inherits from a non-templated Parent class. When I include Child's header in multiple .cpp files I get a LNK2005 error. This happens because Parent gets defined in multiple compilation units. When those units get linked together they cause the LNK2005 error.

In case you're wondering, the purpose of Parent is to give Child one static variable for all Child instance, not just one for each Child< ''type'' >.

My question is, how do I create a templated class which has a unique (across all Child instances) static variable and can be included in multiple .cpp files?

Here's a toy example that causes this LNK2005 error:

main.cpp

#include "Apple.h"
#include "Banana.h"

#include <string>

void main() {
    Apple apple;
    Banana banana;
}

Apple.h

#ifndef APPLE_H
#define APPLE_H

struct Apple {
    Apple();
};

#endif // APPLE_H

Apple.cpp

#include "Apple.h"
#include "Child.h"

Apple::Apple() {
    Child<int> child;
    child.foo(5);
}

Banana.h

#ifndef BANANA_H
#define BANANA_H

struct Banana {
    Banana();
};

#endif // BANANA_H

Banana.cpp

#include "Banana.h"
#include "Child.h"

Banana::Banana() {
    Child<double> child;
    child.foo(3.14);
}

Child.h

#ifndef CHILD_H
#define CHILD_H

#include <iostream>

using namespace std;

///////////// Parent Class Def ///////////

class Parent {
    protected:
    static int id;
};

int Parent::id = 0;

///////////// Child Class Def ///////////

template <class T>
struct Child : protected Parent {
    Child();
    void foo(T t);
};

template <class T>
Child<T>::Child() {
    id++;
}

template <class T>
void Child<T>::foo(T t) {
    cout << "Child" << id << "'s foo() says: " << t << endl;
}

#endif // CHILD_H

error LNK2005: "protected: static int Parent::id" (?id@Parent@@1HA) already defined in Apple.obj

Was it helpful?

Solution

You need to define int Parent::id = 0; just once in Child.C. By including it in the header it gets defined once per file that includes your header.

I suppose I should note that between the evils of putting it in Parent.C (matching class name) or Child.C matching the header name, I picked consistency. Much better is to put Parent in its own files so that you can put the definition in an aptly named Parent.C which still matches the corresponding header name.

OTHER TIPS

Pull

int Parent::id = 0;

out into Parent.cpp and you 'll be fine. What happens now is that the definition gets included once per translation unit that includes Child.h.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top