C++ - 최근 생성된 클래스에 대한 정의되지 않은 참조입니다!
-
05-07-2019 - |
문제
방금 이 새 클래스를 만들었습니다.
//------------------------------------------------------------------------------
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H
//------------------------------------------------------------------------------
#include <vector>
#include <GL/GLFW.h>
//------------------------------------------------------------------------------
template<class T>
class MultithreadedVector {
public:
MultithreadedVector();
void push_back(T data);
void erase(typename std::vector<T>::iterator it);
std::vector<T> get_container();
private:
std::vector<T> container_;
GLFWmutex th_mutex_;
};
//------------------------------------------------------------------------------
#endif // MULTITHREADEDVECTOR_H_INCLUDED
//------------------------------------------------------------------------------
클래스의 정의:
//------------------------------------------------------------------------------
#include "MultithreadedVector.h"
//------------------------------------------------------------------------------
using namespace std;
//------------------------------------------------------------------------------
template<class T>
MultithreadedVector<T>::MultithreadedVector() {
th_mutex_ = glfwCreateMutex();
}
template<class T>
void MultithreadedVector<T>::push_back(T data) {
glfwLockMutex(th_mutex_);
container_.push_back(data);
glfwUnlockMutex(th_mutex_);
}
template<class T>
void MultithreadedVector<T>::erase(typename vector<T>::iterator it) {
glfwLockMutex(th_mutex_);
container_.erase(it);
glfwUnlockMutex(th_mutex_);
}
template<class T>
vector<T> MultithreadedVector<T>::get_container() {
return container_;
}
이제 문제는 내 코드에서 다른 클래스의 정적 멤버로 사용하려고 할 때입니다.
// VehicleManager.h
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H
#include "MultithreadedVector.h"
#include "Vehicle.h"
class Foo {
public:
// stuffs
private:
static MultithreadedVector<Vehicle> vehicles_;
...
}
#endif
그런 다음 내부 :VehicleManager.cpp
#include "VehicleManager.h"
MultithreadedVector<Vehicle> VehicleManager::vehicles_;
void VehicleManager::Method() {
Vehicle vehicle;
VehicleManager::vehicles_.push_back(vehicle);
}
하지만 컴파일되지 않습니다.(, 매번 이 오류 메시지가 나타납니다.
C:\***\VehicleManager.cpp|188|undefined reference to `MultithreadedVector<Vehicle>::push_back(Vehicle)'|
특히 VehicleManager.cpp의 전역 범위에서 정적 클래스 멤버를 정의한 이유를 정말로 이해하지 못합니다.
추신:저는 Code::Blocks를 사용하고 있습니다.
감사해요 !
해결책
이것이 클래스 템플릿 구현을 CPP 파일로 맹목적으로 이동할 때 일어날 일입니다.
해당 작업을 수행하려면 클래스 템플릿을 인스턴스화하고 CPP 파일에 어떤 유형을 인스턴스화 할 것인지 정확히 알아야합니다.
이 경우 이것을 CPP 파일에 넣습니다.
template class MultithreadedVector<Vehicle>;
CPP 파일은 알아야합니다 Vehicle
그 다음에.
다른 팁
대부분의 C++ 컴파일러에서는 템플릿 선언과 템플릿 정의를 분리하는 것을 허용하지 않습니다.템플릿 클래스의 전체 정의를 .h 및 .cpp 파일로 분할하는 것이 아니라 단일 .h 파일에 넣어야 합니다.
템플릿 구현 전체 코드는 템플릿을 사용하는 시점에서 컴파일러에 표시되어 템플릿을 인스턴스화하고 나중에 연결할 수있는 객체 코드로 컴파일 할 수 있어야합니다.
템플릿이 선언 된 것과 동일한 헤더 파일에서 템플릿 코드를 정의하십시오.
템플릿을 사용하는 방법이 두 가지 있다고 생각합니다.
- 임의의 순응 유형 세트에 대한 일반 코드 제공
- 고정 유형 세트에 대한 일반 코드 제공
두 번째의 경우 템플릿을 헤더에 넣을 필요가 없습니다. 템플릿을 사용하는 유형을 사용하여 미리 알고 있으므로 정확하게 알 수 있습니다. 클래스 템플릿의 멤버 함수 또는 링커 오류없이 별도의 번역 장치에서 함수 템플릿을 잘 정의 할 수 있습니다. 어떤 사람들은 다른 사람들에게 이것이 불가능하다고 계속 가르치고 있으며, 이것으로 문제를 혼동합니다.
그러나 나는 그것이 선언과 정의를 다른 번역 단위로 분리할지 여부에 따라이 두 경우에 달려 있다고 생각합니다.
Case 1을 사용하려면 항상 헤더에 정의를 원합니다 (특수 명명 된 파일에 포함 되든
.ipp
,.tcc
또는 무엇이든). 이 경우에도 선언과의 정의를 분리하는 것을 지원하는 하나의 C ++ 프론트 엔드 만 알고 있습니다.export
. 이 키워드는 일부의 키워드로 간주되며 대부분의 컴파일러는이를 구현하지 않습니다.그리고 Case 2를 사용하려면 정의를 헤더에 넣는 것이 좋지 않습니다. 왜냐하면 그렇게 할 이유가 없기 때문입니다. 고정 된 유형 세트에 필요한 기능과 클래스를 명시 적으로 인스턴스화합니다. 이 두 번째 시나리오에서는 템플릿을 사용하여 중복 코드를 유지하기 위해 부담으로부터 자신을 절약하고 경우에 따라 일부 유형에 대해 특별한 동작을 도입 할 수있는 옵션을 열어줍니다.
시나리오는 분명히 사례 1 상황이므로 정의를 헤더에 넣어야합니다.
VehicleManager.h에 복사 및 붙여 넣기 오류가있는 것 같습니다.
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H
이는 클래스 FOO가 정의되는 헤더 파일의 포함을 금지합니다.
대부분의 경우 CPP 파일에 템플릿 구현을 쓸 수 없습니다. 컴파일러가 제대로 인스턴스화 할 수 있도록 템플릿 구현을 헤더 파일로 이동하십시오.
다른 답변과는 별도로 :
당신은 보호해야합니다 get_container()
또한. 이 방법은 기본적으로 복사합니다 container_
요소와 따라서 보호해야합니다.
template<class T>
vector<T> MultithreadedVector<T>::get_container()
{
return container_;
}
어떤 면에서 템플릿은 일종의 고급 특수 매크로입니다.실제로 하려는 것처럼 보이는 것처럼 템플릿 정의를 별도로 컴파일할 수는 없습니다.
대부분의 사람들에게 이는 테플레이트 정의를 선언과 분리하는 데 신경을 쓰지 않는다는 의미입니다.나에겐 동료가 한 명 있는데, 그 사람은 이것을 한 단계 더 발전시킵니다, 그리고 별거를 거부합니다 비템플릿 정의와 선언도 마찬가지입니다.
선언에서 템플릿 정의를 넣으려면 몇 가지 옵션이 있습니다.
첫 번째 옵션은 C++ "내보내기" 키워드를 사용하는 것입니다.겉으로는 간단해 보이는 이 솔루션의 문제점은 다음과 같습니다. 아무도 지지하지 않아.컴파일러 작성자가 구현하기에는 너무 어렵습니다.
두 번째 옵션은 세 번째 유형의 파일, 선언의 경우 종종 ".ipp" 태그가 지정됩니다.여기서 중요한 점은 여전히 "#included"가 되어야 하는 파일이지만 별도의 파일이므로 ".cpp" 파일에만 포함하면 된다는 것입니다.단일 프로그램에서 둘 이상의 ".cpp" 파일에 ".ipp"를 #include하는 경우 내 링커가 이를 좋아하지 않는다는 것을 알았습니다. 따라서 하나를 포함자로 선택해야 합니다.