注册 登录
编程论坛 C++教室

把友元函数的实现写到类的外面去时出现了问题

thlgood 发布于 2013-05-08 17:11, 709 次点击
楼主的程序是这样的
我定义了一个类模板,类模板里面的有一个结构体node:

现在这个类有一个友元函数travels(),当我把这个函数的实现写在类的内部的时候能够正常编译,但是当我把它的实现写到内的外部的时候出现了语法错误

程序代码:

template<typename T>
class rbtree
{
private:
    struct node
    {
        T m_value;    //node也要用到T
        ...
    };
    ...
public:
    ...
    //先序打印红黑树
    friend void travels(rbtree<T>::node* root)
    {
        if (NULL != root)
        {
            //递归调用
            if (NULL != root->m_left) travels(root->m_left);
            cout << root->m_value << endl;
            if (NULL != root->m_right) travels(root->m_right);
        }
    }
};


现在我面临的问题是,如果把友元函数travels()的实现写到类的外面去?
我是这样写的,但是不正确啊
程序代码:

template<typename T>
void travels(rbtree<T>::node* rt)
{
    rbtree::node* r = rt;
    if (r != NULL)
    {
        if(NULL != r->m_left) travels(r->m_left);
        cout << r->m_value << endl;
        if(NULL != r->m_right)travels(r->m_right);
    }
}

语法错误为:
程序代码:

rbTree.cpp:37:47: 警告:友元声明‘void travels(rbtree<T>::node*)’声明了一个非模板函数 [-Wnon-template-friend]
     friend void travels(rbtree<T>::node* rt);
                                               ^
rbTree.cpp:37:47: 附注:(如果这不是您原来的想法,请确定此函数模板已经声明过,并在这里的函数名后面添加 <>)
rbTree.cpp:147:28: 错误:变量或字段‘travels’声明为 void

 void travels(rbtree<T>::node* rt)
                            ^
rbTree.cpp:147:34: 错误:‘rt’在此作用域中尚未声明

 void travels(rbtree<T>::node* rt)


谢谢关注
2 回复
#2
thlgood2013-05-08 17:13
楼上的代码是简化过的代码,如果你觉的我在1L阐述得不够清晰,可以看看完整的代码:
程序代码:

#include <iostream>
#include <queue>
using namespace std;

template<typename T>
class rbtree
{
private:
    enum{RED, BLACK};
    struct node
    {
        T     m_value;
        node* m_left;
        node* m_right;
        node* m_parent;
        int   m_color;

        node(T& value, node* left = NULL, node* right = NULL ,
             node* parent = NULL):
             m_value(value), m_left(left),
             m_right(right), m_parent(parent),
             m_color(BLACK)
        {}
    };

    node* root;
    rbtree(rbtree& rhs);
    rbtree& operator=(rbtree& rhs);
public:
    rbtree(T& value)
    {root = new node(value);}
    rbtree():root(NULL){}

    //insert a value to red black tree
    void insert(T& value);
    //left-middle-right travel
    friend void lmr_travel(rbtree<T>::node* rt);
    //midle-left-right travel
//    friend void mlr_travel(rbTree<T>::node*);
   
//destroy this tree
    void destroy();

    ~rbtree();
};

template<typename T>
void rbtree<T>::insert(T& value)
{
    if (NULL == root)
    {
        root = new node(value);
        return;
    }

    enum{LEFT, RIGHT};
    int positon = LEFT;
    node* nodep = root;
    while(true)
    {
        if (value > nodep->m_value)
        {
            if (NULL != nodep->m_right)
            {
                nodep = nodep->m_right;
                continue;
            }
            positon = RIGHT;
            break;
        }
        else if (value < nodep->m_value)
        {
            if (NULL != nodep->m_left)
            {
                nodep = nodep->m_left;
                continue;
            }
            positon = LEFT;
            break;
        }
        else
        {
            return;
        }
    }
    if (nodep->m_color = BLACK)
    {
        if (positon == LEFT)
        {
            nodep->m_left = new node(value);
            nodep->m_left->m_parent = nodep;
            nodep->m_left->m_color = RED;
        }
        else
        {
            nodep->m_right = new node(value);
            nodep->m_right->m_parent = nodep;
            nodep->m_right->m_color = RED;
        }
    }
}

template<typename T>
rbtree<T>::~rbtree()
{
    destroy();
}

template<typename T>
void rbtree<T>::destroy()
{
    queue<node *>rbqueue;
    rbqueue.push(root);
    node* tmp;
    while(!rbqueue.empty())
    {
        tmp = rbqueue.front();
        if (tmp != NULL)
        {
            if (NULL != tmp->m_left)
            {
                rbqueue.push(tmp->m_left);
            }
            if (NULL != tmp->m_right)
            {
                rbqueue.push(tmp->m_right);
            }
            delete tmp;
        }
        rbqueue.pop();
    }
    root = NULL;
}
/*
template<typename T>
void lmr_travel(rbtree<T>::node* rt)
{
    rbTree::node* r = rt;
    if (r != NULL)
    {
        help_travel(r->m_left);
        cout << r->value << endl;
        help_travel(r->m_right);
    }
}
*/
template<typename T>
void lmr_travel(rbtree<T>::node* rt)
{
    rbtree::node* r = rt;
    if (r != NULL)
    {
        if(NULL != r->m_left)
            lmr_travel(r->m_left);
        cout << r->value << endl;
        if(NULL != r->m_right)
            lmr_travel(r->m_right);
    }
}
int main()
{
    rbtree<int> t;
    return 0;
}


[ 本帖最后由 thlgood 于 2013-5-8 17:14 编辑 ]
#3
rjsp2013-05-09 09:11
你基础知识缺乏,有太多错误,我只能挑重要的讲一下

程序代码:
template<typename T>
class foo
{
private:
    struct node
    {
        T value;
    };
public:
    friend void bar( typename foo<T>::node* root )
    {
        root->value = 1;
    }
};
写在里面,这是定义了一个 友元普通函数

程序代码:
template<typename T>
class foo
{
private:
    struct node
    {
        T value;
    };
public:
    template<typename T> friend void bar( typename foo<T>::node* root );
};

template<typename T>
void bar( typename foo<T>::node* root )
{
    root->value = 1;
}
写在外面,这是定义了一个 友元模板函数
但此时,所有bar都是foo的友元,即bar<double>也会是foo<int>的友元,所以最正确的写法是
程序代码:
template<typename T> class foo;
template<typename T> void bar( typename foo<T>::node* root );

template<typename T>
class foo
{
private:
    struct node
    {
        T value;
    };
public:
    friend void bar<T>( typename foo<T>::node* root );
    friend int main();
};

template<typename T>
void bar( typename foo<T>::node* root )
{
    root->value = 1;
}

1