Шаблонный класс с не шаблонной базой выдает ошибку LNK2005 - PullRequest
2 голосов
/ 22 марта 2011

У меня есть шаблонный класс Child , который наследуется от не шаблонного Parent класса.Когда я включаю заголовок Child в несколько файлов .cpp, я получаю ошибку LNK2005.Это происходит потому, что Parent определяется в нескольких единицах компиляции.Когда эти блоки связаны друг с другом, они вызывают ошибку LNK2005.

Если вам интересно, цель Parent - дать Child одну статическую переменную для всех Дочерний экземпляр, а не только один для каждого Дочерний <'' тип ''> .

Мой вопрос: как мне создать шаблонный класс, который имеет уникальный(для всех дочерних экземпляров) статическая переменная и может быть включена в несколько файлов .cpp?

Вот игрушечный пример, который вызывает эту ошибку LNK2005:

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

ошибка LNK2005: «protected: static int Parent :: id» (? Id @ Parent @@ 1HA) уже определено в Apple.obj

Ответы [ 2 ]

6 голосов
/ 22 марта 2011

Вам нужно определить int Parent::id = 0; только один раз в Child.C. Включив его в заголовок, он определяется один раз для файла, который включает в себя ваш заголовок.

Полагаю, я должен заметить, что между злом, связанным с Parent.C (соответствующим именем класса) или Child.C, соответствующим имени заголовка, я выбрал последовательность. Гораздо лучше поместить Parent в свои собственные файлы, чтобы вы могли поместить определение в метко названное Parent.C, которое по-прежнему совпадает с соответствующим именем заголовка.

1 голос
/ 22 марта 2011

Потяните

int Parent::id = 0;

в Parent.cpp, и все будет в порядке.Теперь происходит то, что определение включается один раз за единицу перевода, которая включает Child.h.

...