我正在将AVL树作为库的一部分实现,无法确定是CppUnit,NetBeans 8,我的C ++技能(模板)还是其他问题,但是代码可以作为静态库编译,但是当与CppUnit或独立应用程序一起使用时,我得到undefined reference to MyProject::Utilities::AVLTree<int, char>::function
。
我尽可能减少了代码,同时仍然保持相同的错误。
AVLTree.h
namespace MyProject {
namespace Utilities {
template <typename KeyType, typename ValueType> class AVLTree {
public:
AVLTree();
AVLTree(const MyProject::Utilities::AVLTree<KeyType, ValueType>& orig);
virtual ~AVLTree();
bool hasRoot() const;
MyProject::Utilities::AVLNode<KeyType, ValueType>* getRoot() const;
protected:
void setRoot(MyProject::Utilities::AVLNode<KeyType, ValueType>* _node);
private:
MyProject::Utilities::AVLNode<KeyType, ValueType>* _root;
unsigned int _size;
};
};
};
AVLTree.cpp
template <typename KeyType, typename ValueType> MyProject::Utilities::AVLTree<KeyType, ValueType>::AVLTree() {
this->setRoot(NULL);
this->_size = 0;
}
template <typename KeyType, typename ValueType> MyProject::Utilities::AVLTree<KeyType, ValueType>::AVLTree(const MyProject::Utilities::AVLTree<KeyType, ValueType>& orig) {
this->setRoot(orig.getRoot());
this->_size = orig.size();
}
template <typename KeyType, typename ValueType> MyProject::Utilities::AVLTree<KeyType, ValueType>::~AVLTree() {
// this->clear();
}
template <typename KeyType, typename ValueType> void MyProject::Utilities::AVLTree<KeyType, ValueType>::setRoot(MyProject::Utilities::AVLNode<KeyType, ValueType>* _root) {
this->_root = _root;
}
template <typename KeyType, typename ValueType> bool MyProject::Utilities::AVLTree<KeyType, ValueType>::hasRoot() const {
return this->getRoot() != NULL;
}
template <typename KeyType, typename ValueType> MyProject::Utilities::AVLNode<KeyType, ValueType>* MyProject::Utilities::AVLTree<KeyType, ValueType>::getRoot() const {
return this->_root;
}
main.cpp
#include <cstdlib>
#include "AVLTree.h"
int main(int argc, char** argv) {
MyProject::Utilities::AVLTree<int, char> instance;
for (unsigned int i = 0; i < 20; ++i) {
instance.hasRoot();
// instance.insert(i, (char) (65 + i));
}
//instance.graphviz("./test.dot");
return 0;
}
尝试构建cppapplication_1时,Netbeans 8返回以下错误
g++ -c -g -I../../Documents/MyProject/src/header -MMD -MP -MF "build/Debug/GNU-Linux-x86/main.o.d" -o build/Debug/GNU-Linux-x86/main.o main.cpp
mkdir -p dist/Debug/GNU-Linux-x86
g++ -o dist/Debug/GNU-Linux-x86/cppapplication_1 build/Debug/GNU-Linux-x86/main.o -L../../Documents/MyProject/dist/Debug/GNU-Linux-x86 -lmyproject
build/Debug/GNU-Linux-x86/main.o: In function `main':
/home/.../CppApplication_1/main.cpp:6: undefined reference to `MyProject::Utilities::AVLTree<int, char>::AVLTree()'
/home/.../CppApplication_1/main.cpp:8: undefined reference to `MyProject::Utilities::AVLTree<int, char>::hasRoot() const'
/home/.../CppApplication_1/main.cpp:12: undefined reference to `MyProject::Utilities::AVLTree<int, char>::~AVLTree()'
/home/.../CppApplication_1/main.cpp:12: undefined reference to `MyProject::Utilities::AVLTree<int, char>::~AVLTree()'
collect2: error: ld returned 1 exit status
。
。
。
。
。
。
下面的代码会产生大约100个不同内容的错误...我并不是说傻瓜,但对于我一生来说,我无法弄清楚出什么问题了,也找不到适合的示例或教程。 ..
src/header/AVLTree.h:16:23: error: declaration of ‘class KeyType’
template <typename KeyType, typename ValueType> AVLTree();
src/header/AVLTree.h:14:19: error: shadows template parm ‘class KeyType’
template <typename KeyType, typename ValueType> class AVLTree {
src/header/AVLTree.h:16:41: error: declaration of ‘class ValueType’
template <typename KeyType, typename ValueType> AVLTree();
src/header/AVLTree.h:14:37: error: shadows template parm ‘class ValueType’
template <typename KeyType, typename ValueType> class AVLTree {
In file included from src/AVLTree.cpp:1:0:
src/header/AVLTree.h:18:23: error: declaration of ‘class KeyType’
template <typename KeyType, typename ValueType> virtual ~AVLTree();
AVLTree.h
namespace MyProject {
namespace Utilities {
template <typename KeyType, typename ValueType> class AVLTree {
public:
template <typename KeyType, typename ValueType> AVLTree();
template <typename KeyType, typename ValueType> AVLTree(const MyProject::Utilities::AVLTree<KeyType, ValueType>& orig);
template <typename KeyType, typename ValueType> virtual ~AVLTree();
template <typename KeyType, typename ValueType> bool hasRoot() const;
template <typename KeyType, typename ValueType> MyProject::Utilities::AVLNode<KeyType, ValueType>* getRoot() const;
protected:
void setRoot(MyProject::Utilities::AVLNode<KeyType, ValueType>* _node);
private:
MyProject::Utilities::AVLNode<KeyType, ValueType>* _root;
};
};
};
AVLTree.cpp(指定类型)
MyProject::Utilities::AVLTree<KeyType, ValueType>::AVLTree() {
this->setRoot(NULL);
}
MyProject::Utilities::AVLTree<KeyType, ValueType>::AVLTree(const MyProject::Utilities::AVLTree<KeyType, ValueType>& orig) {
this->setRoot(orig.getRoot());
// this->_size = orig.size();
}
MyProject::Utilities::AVLTree<KeyType, ValueType>::~AVLTree() {
// this->clear();
}
void MyProject::Utilities::AVLTree<KeyType, ValueType>::setRoot(MyProject::Utilities::AVLNode<KeyType, ValueType>* _root) {
this->_root = _root;
}
bool MyProject::Utilities::AVLTree<KeyType, ValueType>::hasRoot() const {
return this->getRoot() != NULL;
}
MyProject::Utilities::AVLNode<KeyType, ValueType>* MyProject::Utilities::AVLTree<KeyType, ValueType>::getRoot() const {
return this->_root;
}
AVLTree.cpp(类型未指定)
MyProject::Utilities::AVLTree::AVLTree() {
this->setRoot(NULL);
}
MyProject::Utilities::AVLTree::AVLTree(const MyProject::Utilities::AVLTree& orig) {
this->setRoot(orig.getRoot());
// this->_size = orig.size();
}
MyProject::Utilities::AVLTree::~AVLTree() {
// this->clear();
}
void MyProject::Utilities::AVLTree::setRoot(MyProject::Utilities::AVLNode<KeyType, ValueType>* _root) {
this->_root = _root;
}
bool MyProject::Utilities::AVLTree::hasRoot() const {
return this->getRoot() != NULL;
}
MyProject::Utilities::AVLNode<KeyType, ValueType>* MyProject::Utilities::AVLTree::getRoot() const {
return this->_root;
}
最佳答案
模板不是功能。它们在代码中不存在。它们只是一种蓝图,或者是有关所有模板参数已知后如何实际实现功能的说明。因此,所有模板都必须驻留在头文件中,以便在知道所有模板参数后才可见。将所有模板代码从AVLTree.cpp移到AVLTree.h。仅仅移动还不够,还必须更改它。
这是在我的Visual Studio上编译的示例:
namespace My {
namespace Util {
template <typename KeyType, typename ValueType> class World {
public:
World()
{
}
World(const My::Util::World<KeyType, ValueType>& orig)
{
}
virtual ~World()
{
}
bool Hello() const
{
return true;
}
};
};
};
使用如下代码:
My::Util::World<int, char> world;
world.Hello();
可以将所有函数与类声明分开,但这没有实际用途,因为所有分开的代码无论如何都必须是可见的。它看起来像这样:
namespace My {
namespace Util {
template <typename KeyType, typename ValueType> class World {
....
bool Hello() const;
};
};
};
template<typename KeyType, typename ValueType>
bool My::Util::World<KeyType, ValueType>::Hello() const
{
return true;
}
我尝试了您的示例,它对我有用。我只是将所有函数模板放在类模板之后,并注释掉所有处理
AVLNode
的代码,然后对其进行编译。因此,我的原始声明似乎是有效的:只需将所有模板代码从源代码移至标头即可。您的第二个示例代码与第一个示例代码不同。您应该做的只是移动。