zoukankan      html  css  js  c++  java
  • c++类模板之间友元函数调用

     1 #include <stdio.h>
     2 #include <iostream>
     3 
     4 using namespace std;
     5 
     6 template<typename T> class BTree;
     7 
     8 /***************************节点类模板*********************************/
     9 template<typename T>
    10 class BTreeNode{
    11     friend void BTree<T>::Print(BTreeNode<T> *t);
    12     friend void BTree<T>::PreOrder(BTreeNode<T> *t);
    13     friend int BTree<T>::Deepth(BTreeNode<T> *t);
    14     friend void BTree<T>::Insert(BTreeNode<T> *t, int n);
    15 
    16 public:
    17     BTreeNode(){ data = NULL; left = right = NULL; }
    18     BTreeNode(const T& val){ data = val; left = right = NULL; }
    19     BTreeNode(const T& val, BTreeNode<T> *l, BTreeNode<T> *r){ data = val; left = l; right = r; }
    20     ~BTreeNode(){ delete left; delete right; }
    21 
    22 private:
    23     T data;
    24     BTreeNode<T> *left;
    25     BTreeNode<T> *right;
    26 };
    27 
    28 /***************************树类模板**********************************/
    29 template<typename T>
    30 class BTree{
    31 public:
    32     void Print(BTreeNode<T> *t);
    33     void PreOrder(BTreeNode<T> *t);
    34     int Deepth(BTreeNode<T> *t);
    35     void Insert(BTreeNode<T> *t,int n);
    36 private:
    37     BTreeNode<T> *root;
    38 };
    39 
    40 template<typename T>
    41 void BTree<T>::Print(BTreeNode<T> *t)
    42 {
    43     cout << t->data << endl;
    44 }
    45 
    46 
    47 template<typename T> 
    48 void BTree<T>::PreOrder(BTreeNode<T> *t)
    49 {
    50     if (t != NULL)
    51     {
    52         Print(t);
    53         PreOrder(t->left);
    54         PreOrder(t->right);
    55     }
    56 }
    57 
    58 template<typename T> 
    59 int BTree<T>::Deepth(BTreeNode<T> *t)
    60 {
    61     if (t == NULL)
    62     {
    63         return 0;
    64     }
    65     int left = 1;
    66     int right = 1;
    67     left += Deepth(t->left);
    68     right += Deepth(t->right);
    69     return left >= right ? left : right;
    70 }
    71 
    72 //右边的节点比左边大10
    73 template<typename T>
    74 void BTree<T>::Insert(BTreeNode<T> *t, int n)
    75 {
    76     if (n < 0)
    77     {
    78         return;
    79     }
    80     int i = ii;
    81     t->left = new BTreeNode<T>(ii++);
    82     //i = ii;
    83     Insert(t->left, n - 1);
    84     t->right = new BTreeNode<T>(i + 10);
    85     Insert(t->right, n - 1);
    86 }

    友元函数可以访问封装好的类的私有成员,无疑破坏了类的封装性。不过确实可以提高很多发开的效率。
    以前用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()什么。其实先写定义头是个好习惯!!!

  • 相关阅读:
    ubuntu安装后要做什么
    JavaScript错误处理
    jQuery 事件
    display的用法
    百度排名的原理
    什么是ajax?
    CSS文档流
    引用CSS的方法
    jQuery的安装方式
    禁止WPS2019开机自启动
  • 原文地址:https://www.cnblogs.com/wyc199288/p/4989851.html
Copyright © 2011-2022 走看看