您的位置:首页 > 编程语言 > C语言/C++

c++类模板之间友元函数调用

2015-11-23 22:05 260 查看
#include <stdio.h>
#include <iostream>

using namespace std;

template<typename T> class BTree;

/***************************节点类模板*********************************/
template<typename T>
class BTreeNode{
friend void BTree<T>::Print(BTreeNode<T> *t);
friend void BTree<T>::PreOrder(BTreeNode<T> *t);
friend int BTree<T>::Deepth(BTreeNode<T> *t);
friend void BTree<T>::Insert(BTreeNode<T> *t, int n);

public:
BTreeNode(){ data = NULL; left = right = NULL; }
BTreeNode(const T& val){ data = val; left = right = NULL; }
BTreeNode(const T& val, BTreeNode<T> *l, BTreeNode<T> *r){ data = val; left = l; right = r; }
~BTreeNode(){ delete left; delete right; }

private:
T data;
BTreeNode<T> *left;
BTreeNode<T> *right;
};

/***************************树类模板**********************************/
template<typename T>
class BTree{
public:
void Print(BTreeNode<T> *t);
void PreOrder(BTreeNode<T> *t);
int Deepth(BTreeNode<T> *t);
void Insert(BTreeNode<T> *t,int n);
private:
BTreeNode<T> *root;
};

template<typename T>
void BTree<T>::Print(BTreeNode<T> *t)
{
cout << t->data << endl;
}

template<typename T>
void BTree<T>::PreOrder(BTreeNode<T> *t)
{
if (t != NULL)
{
Print(t);
PreOrder(t->left);
PreOrder(t->right);
}
}

template<typename T>
int BTree<T>::Deepth(BTreeNode<T> *t)
{
if (t == NULL)
{
return 0;
}
int left = 1;
int right = 1;
left += Deepth(t->left);
right += Deepth(t->right);
return left >= right ? left : right;
}

//右边的节点比左边大10
template<typename T>
void BTree<T>::Insert(BTreeNode<T> *t, int n)
{
if (n < 0)
{
return;
}
int i = ii;
t->left = new BTreeNode<T>(ii++);
//i = ii;
Insert(t->left, n - 1);
t->right = new BTreeNode<T>(i + 10);
Insert(t->right, n - 1);
}

友元函数可以访问封装好的类的私有成员,无疑破坏了类的封装性。不过确实可以提高很多发开的效率。
以前用c语言写链表等,都用结构体来定义一个点。在c++中,用类代替了结构体:确实,类和结构体差不多,只是类可以有私有变量,而结构体都是公有的。
在写二叉树时发现了这样写需要注意的。
代码在上面。main就不写了。
首先要写一个节点类:


/***************************节点类模板*********************************/
template<typename T>
class BTreeNode{
friend void BTree<T>::Print(BTreeNode<T> *t);
friend void BTree<T>::PreOrder(BTreeNode<T> *t);
friend int BTree<T>::Deepth(BTreeNode<T> *t);
friend void BTree<T>::Insert(BTreeNode<T> *t, int n);

public:
BTreeNode(){ data = NULL; left = right = NULL; }
BTreeNode(const T& val){ data = val; left = right = NULL; }
BTreeNode(const T& val, BTreeNode<T> *l, BTreeNode<T> *r){ data = val; left = l; right = r; }
~BTreeNode(){ delete left; delete right; }

private:
T data;
BTreeNode<T> *left;
BTreeNode<T> *right;
};


除了基本的声明,再声明几个友元函数给之后的BTree类调用,BTreeNode只是表示节点,而树是很多节点相连的。所以下面写BTree类,实现树的一些功能。需要注意的是:声明友元的时候,不能跟普通的外部函数一样,声明类或类模板的函数,需要加上域的限制。想想也是,否则编译器怎么能之后你要调用到底是哪个函数呢?因为假如在类内还类外都有同一个名字的函数,那就出事了。所以限定域肯定是有的!!!

/***************************树类模板**********************************/
template<typename T>
class BTree{
public:
void Print(BTreeNode<T> *t);
void PreOrder(BTreeNode<T> *t);
int Deepth(BTreeNode<T> *t);
void Insert(BTreeNode<T> *t,int n);
private:
BTreeNode<T> *root;
};

template<typename T>
void BTree<T>::Print(BTreeNode<T> *t)
{
cout << t->data << endl;
}

template<typename T>
void BTree<T>::PreOrder(BTreeNode<T> *t)
{
if (t != NULL)
{
Print(t);
PreOrder(t->left);
PreOrder(t->right);
}
}

template<typename T>
int BTree<T>::Deepth(BTreeNode<T> *t)
{
if (t == NULL)
{
return 0;
}
int left = 1;
int right = 1;
left += Deepth(t->left);
right += Deepth(t->right);
return left >= right ? left : right;
}

//右边的节点比左边大10
template<typename T>
void BTree<T>::Insert(BTreeNode<T> *t, int n)
{
if (n < 0)
{
return;
}
int i = ii;
t->left = new BTreeNode<T>(ii++);
//i = ii;
Insert(t->left, n - 1);
t->right = new BTreeNode<T>(i + 10);
Insert(t->right, n - 1);
}


可以看到,在类模板里还是跟正常一样声明函数,和在类外定义函数。但是当你在主函数使用这些定义的函数就会出错。那是因为在定义友元的时候没有声明类模板。

在第一个类模板就是BTreeNode之前就上很重要的一句:

template<typename T> class BTree;


就完美了。另外记住:以后在使用之前先声明,否则无论是使用和定义都会出现问题。

我写程序一直都是class什么,class什么,int main()什么。其实先写定义头是个好习惯!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: