547658697 发表于 2021-3-11 15:21:21

C++中关于模板类定义失败的问题

问题:我已经在.cpp文件中对声明进行了定义,但是却报错undefined reference to `BTnode<int>::BTnode(int const&)'| ,这是为什么

代码如下:

头文件:
//.h文件中,对二叉树结点类声明

#ifndef BTNODE_H_INCLUDED
#define BTNODE_H_INCLUDED

template <typename valType>
class BTnode
{
public:
    //...
    BTnode(const valType &val);
    //...
private:
   valType _val;
   int _cnt;
   BTnode* _lchild;
   BTnode* _rchild;
};

#endif


源文件:
//.cpp文件中对BTnode(const valType &val) 进行定义
#include “BTnode.h”

template <typename valType>
inline BTnode<valType>::
    BTnode(const valType &val):_val(val)
    {
      _cnt=1;
      _lchild=_rchild=0;
    }

main函数:
#include <iostream>
#include "BinaryTree.h"
#include "BTnode.h"
#include <string.h>

using namespace std;

int main()
{
    BTnode<int> bt(3);
    return 0;
}

程序报错:
undefined reference to `BTnode<int>::BTnode(int const&)'|

问题:我已经在.cpp文件中对声明进行了定义,但是却报错undefined reference to `BTnode<int>::BTnode(int const&)'| ,这是为什么?

人造人 发表于 2021-3-11 15:37:00

有个问题,这个是BinaryTree.h 文件的内容?
源文件:
//.cpp文件中对BTnode(const valType &val) 进行定义
#include “BTnode.h”

template <typename valType>
inline BTnode<valType>::
    BTnode(const valType &val):_val(val)
    {
      _cnt=1;
      _lchild=_rchild=0;
    }

547658697 发表于 2021-3-11 15:40:12

人造人 发表于 2021-3-11 15:37
有个问题,这个是BinaryTree.h 文件的内容?

这个是我.BTnode.cpp文件的内容,用来对BTnode.h当中的所有类声明进行定义,在这里我只截取了一部分。

人造人 发表于 2021-3-11 15:44:10

547658697 发表于 2021-3-11 15:40
这个是我.BTnode.cpp文件的内容,用来对BTnode.h当中的所有类声明进行定义,在这里我只截取了一部分。

把所有的源代码都贴出来,说明哪一个代码在哪一个源文件,我在这边帮你看看

547658697 发表于 2021-3-11 15:55:32

人造人 发表于 2021-3-11 15:44
把所有的源代码都贴出来,说明哪一个代码在哪一个源文件,我在这边帮你看看

感谢!下面是我所有的代码,每个开头都标有文件名字,现在是测试BTnode模板实例化就出现了问题。

main.cpp
#include <iostream>
#include "BinaryTree.h"
#include "BTnode.h"
#include <string.h>

using namespace std;

template <typename elemType>
ostream& operator << (ostream &os, BinaryTree<elemType> &bt)
{
    return bt.print(os);
}

int main()
{
    BTnode<int> bt(3);
    return 0;
}


BTnode.h
#ifndef BTNODE_H_INCLUDED
#define BTNODE_H_INCLUDED

template <typename Type>
class BinaryTree;

template <typename valType>
class BTnode
{
public:
    friend class BinaryTree<valType>;
    BTnode(const valType &val);
    void insert_value( const valType &val);
    void lchild_leaf(BTnode<valType> *leaf,BTnode<valType> *subtree );
    void remove_value(valType &val , BTnode<valType> *prev);
private:
   valType _val;
   int _cnt;
   BTnode* _lchild;
   BTnode* _rchild;
};

#endif // BTNODE_H_INCLUDED


BTnode.cpp
#include "BTnode.h"


template <typename valType>
inline BTnode<valType>::
    BTnode(const valType &val):_val(val)
    {
      _cnt=1;
      _lchild=_rchild=0;
    }


template <typename valType>
inline void BTnode<valType>::
    insert_value ( const valType &val )
    {
      if(_val == val )
            _cnt++;
      if(_val < val)
      {
            if(! _lchild)
                _lchild = new BTnode<valType>(val);
            else
                _lchild->insert_value(val);
      }
      if(_val > val)
      {
            if(! _rchild)
                _rchild = new BTnode<valType>(val);
            else
                _rchild->insert_value(val);
      }
    }

template <typename valType>
inline void BTnode<valType>::
    lchild_leaf(BTnode<valType> *leaf,BTnode<valType> *subtree )
    {
      //找到没有左孩子的结点
      while (! subtree->_lchild )
            subtree = subtree->_lchild;
      //找到了 subtree所指结点没有左子树
      subtree->_lchild = leaf;
    }

template <typename valType>
inline void BTnode<valType>::
    remove_value(valType &val , BTnode<valType> *prev)
    {
      if (val < _val)
      {
            if( !_lchild )
                return ;
            else
            {
                _lchild->remove_value(val,_lchild);
            }
      }
      else
      if (val > _val)
      {
            if( !_rchild )
                return ;
            else
            {
                _rchild->remove_value(val,_rchild);
            }
      }
      else
      {
            if(_rchild)
            {
                prev = _rchild;
                if(_lchild)
                {
                  if(!prev -> _lchild )
                        prev->_lchild =_lchild;
                  else
                      BTnode<valType>::lchild_leaf(_lchild,prev->_lchild);
                }
            }
            else
                prev = _lchild;
            delete this;

      }
    }



BinaryTree.h
#ifndef BINARYTREE_H_INCLUDED
#define BINARYTREE_H_INCLUDED

#include "BTnode.h"
#include <iostream>
using namespace std;

template <typename elemType>
class BinaryTree
{
public:
    BinaryTree() ;
    BinaryTree(const BinaryTree& );
    ~BinaryTree() ;
    BinaryTree& operator = (const BinaryTree& );
    ostream& print(ostream& os) const ; //中序遍历

    void insert(const elemType &elem);
    void remove( const elemType &elem);
    void remove_root( const elemType &elem);
    bool empty() {return _root;}
    void clear();
private:
    void clear(BTnode<elemType> *pt);
    BTnode<elemType>* _root;
    void copy(BTnode<elemType> *tar,BTnode<elemType> *src);
};

#endif // BINARYTREE_H_INCLUDED

BinaryTree.cpp
#include "BinaryTree.h"

template <typename elemType>
inline BinaryTree<elemType>::BinaryTree() :_root(0) {}

template <typename elemType>
inline BinaryTree<elemType>::BinaryTree(const BinaryTree &rhs)
    {
      copy(_root,rhs._root);
    }

template <typename elemType>
inline BinaryTree<elemType>::~BinaryTree()
    {
      clear();
    }

template <typename elemType>
inline BinaryTree<elemType>&
BinaryTree<elemType>::
    operator =(const BinaryTree &rhs)
    {
      if(this != rhs)
            clear();
      copy(_root,rhs._root);
      return *this;
    }

template <typename elemType>
inline void BinaryTree<elemType>::
    insert(const elemType &elem)
    {
      if( ! _root )
            _root = new BTnode<elemType>(elem);
      else
            _root->inset_value(elem);
    }

template <typename elemType>
inline void BinaryTree<elemType>::
    remove(const elemType &elem)
    {
      if (_root)
      {
            if(_root->_val == elem)
                remove_root();//删除根节点
            else
                _root->remove_value(elem , _root); // 删除_root二叉树中的值为elem的结点
      }
    }

template <typename elemType>
inline void BinaryTree<elemType>::
    remove_root (const elemType &elem)
    {
      BTnode<elemType> *p = _root; //指向准备删除的根节点
      if (! _root)
            return ;
      if (_root->_rchild)
      {
            _root = _root->_rchild;
            if( _root->_lchild )
            {
                BTnode<elemType> *lc = p->_lchild;//指向待处理的根节点的左子树
                BTnode<elemType> *newlc = _root->_lchild;//新根节点的左子树
                if(! newlc)
                  _root->_rchild = lc;
                else
                  BTnode<elemType>::lchild_leaf(lc ,newlc);
            }
      }
      else
            _root = p->_lchild;
      delete p;
    }


template <typename elemType>
inline void
BinaryTree<elemType>::
    clear()
    {
      if(_root)
      {
            clear(_root);
            _root = 0;
      }
    }

template<typename elemType>
inline void
BinaryTree<elemType>::
    clear(BTnode<elemType> *pt)
    {
      if(pt)
      {
            clear(pt->_lchild);
            clear(pt->_rchild);
            delete(pt);
      }
    }

template <typename elemType>
inline ostream&
BinaryTree<elemType>::print(ostream& os) const
{
    if( _root )
    {
      os << print( _root->_lchild );
      os << _root->_val << ' ';
      os << print( _root->_rchild );
    }
    return os;
}

547658697 发表于 2021-3-11 15:57:59

人造人 发表于 2021-3-11 15:44
把所有的源代码都贴出来,说明哪一个代码在哪一个源文件,我在这边帮你看看

BTnode模板实例化出现了问题,问题应该就在BTnode.cpp当中,因为我尝试直接在BTnode.h上,在类内部定义,没有出现问题。

人造人 发表于 2021-3-11 16:08:05

547658697 发表于 2021-3-11 15:57
BTnode模板实例化出现了问题,问题应该就在BTnode.cpp当中,因为我尝试直接在BTnode.h上,在类内部定义, ...

对,没错
模板的声明和定义不能分开,把 BTnode.cpp 的内容合并到 BTnode.h 就可以了
#ifndef BTNODE_H_INCLUDED
#define BTNODE_H_INCLUDED

template <typename Type>
class BinaryTree;

template <typename valType>
class BTnode
{
public:
    friend class BinaryTree<valType>;
    BTnode(const valType &val);
    void insert_value( const valType &val);
    void lchild_leaf(BTnode<valType> *leaf,BTnode<valType> *subtree );
    void remove_value(valType &val , BTnode<valType> *prev);
private:
   valType _val;
   int _cnt;
   BTnode* _lchild;
   BTnode* _rchild;
};

template <typename valType>
inline BTnode<valType>::
    BTnode(const valType &val):_val(val)
    {
      _cnt=1;
      _lchild=_rchild=0;
    }


template <typename valType>
inline void BTnode<valType>::
    insert_value ( const valType &val )
    {
      if(_val == val )
            _cnt++;
      if(_val < val)
      {
            if(! _lchild)
                _lchild = new BTnode<valType>(val);
            else
                _lchild->insert_value(val);
      }
      if(_val > val)
      {
            if(! _rchild)
                _rchild = new BTnode<valType>(val);
            else
                _rchild->insert_value(val);
      }
    }

template <typename valType>
inline void BTnode<valType>::
    lchild_leaf(BTnode<valType> *leaf,BTnode<valType> *subtree )
    {
      //找到没有左孩子的结点
      while (! subtree->_lchild )
            subtree = subtree->_lchild;
      //找到了 subtree所指结点没有左子树
      subtree->_lchild = leaf;
    }

template <typename valType>
inline void BTnode<valType>::
    remove_value(valType &val , BTnode<valType> *prev)
    {
      if (val < _val)
      {
            if( !_lchild )
                return ;
            else
            {
                _lchild->remove_value(val,_lchild);
            }
      }
      else
      if (val > _val)
      {
            if( !_rchild )
                return ;
            else
            {
                _rchild->remove_value(val,_rchild);
            }
      }
      else
      {
            if(_rchild)
            {
                prev = _rchild;
                if(_lchild)
                {
                  if(!prev -> _lchild )
                        prev->_lchild =_lchild;
                  else
                        BTnode<valType>::lchild_leaf(_lchild,prev->_lchild);
                }
            }
            else
                prev = _lchild;
            delete this;

      }
    }

#endif // BTNODE_H_INCLUDED

547658697 发表于 2021-3-11 16:15:32

人造人 发表于 2021-3-11 16:08
对,没错
模板的声明和定义不能分开,把 BTnode.cpp 的内容合并到 BTnode.h 就可以了

非常感谢!问题解决了。
页: [1]
查看完整版本: C++中关于模板类定义失败的问题