C++篇---訪問私有成員的3種情況及友元函數的使用

1. 友元函數

友元函數引入:
  • 私有成員對於類外部的所有程序部分而言都是隱藏的,訪問它們需要調用一個公共成員函數,但有時也可能會需要創建該規則的一項例外。

  • 友元函數是一個不屬於類成員的函數,但它可以訪問該類的私有成員。換句話說,友元函數被視爲好像是該類的一個成員。友元函數可以是常規的獨立函數,也可以是其他類的成員。實際上,整個類都可以聲明爲另一個類的友元。

  • 爲了使一個函數或類成爲另一個類的友元,必須由授予它訪問權限的類來聲明。類保留了它們的朋友的 “名單”,只有名字出現在列表中的外部函數或類才被授予訪問權限。通過將關鍵字 friend 放置在函數的原型之前,即可將函數聲明爲友元。

友元函數說明
  • 必須在類的說明中說明友元函數,說明時以關鍵字friend開頭,後跟友元函數的函數原型,友元函數的說明可以出現在類的任何地方,包括在private和public部分;
  • 注意友元函數不是類的成員函數,所以友元函數的實現和普通函數一樣,在實現時不用"::“指示屬於哪個類,只有成員函數才使用”::"作用域符號;
  • 友元函數不能直接訪問類的成員,只能訪問對象成員,
  • 友元函數可以訪問對象的私有成員,但普通函數不行;
  • 調用友元函數時,在實際參數中需要指出要訪問的對象,
  • 類與類之間的友元關係不能繼承。
  • 一個類的成員函數也可以作爲另一個類的友元,但必須先定義這個類。

2. 訪問私有成員的3種情況

No.1
  • 說明: 一個全局函數想訪問一個類對象的私有成員
  • 解決方法: 在該類中把那個全局函數定義爲該類的友元函數
  • 舉例:
    #include<iostream>
    #include <math.h>
    using namespace std;
    class Point
    {
        int x, y;
    public:
        Point(int x= 0, int y = 0);
        void disp();
        // 友元函數的聲明
        friend double dist(Point p1, Point p2);
    };
    
    Point::Point(int x, int y)
    { this->x = x; this->y = y; }
    
    void Point::disp()
    { cout << '(' << x << ',' << y << ')' << endl;}
    
    // 因訪問類對象的私有屬性,在類中定義友元函數
    double dist(Point p1, Point p2)
    {
        double x = p1.x - p2.x;
        double y = p1.y - p2.y;
        return sqrt(x*x+y*y);
    }
    
    int main()
    {
        Point p1(0,0), p2(1,1);
        double dis = dist(p1,p2);
        cout << "distance of p1 and p2: " << dis << endl;
        system("pause"); return 0;
    }
    
No.2
  • 說明: 一個類中的成員函數想訪問另一個類對象的私有成員
  • 解決方法: 可以在被訪問對象類中定義該函數爲友元函數
  • 舉例:
    #include<string>
    #include<iostream>
    using namespace std;
    
    class Teacher; // 聲明類
    
    class Student
    {
        string name;
        int age;
        int score;
    public:
        Student(){};
        Student(string name="onname", int age=18);
        void disp();
        // 定義Teacher類的setScore成員函數爲該類的友元函數
        friend void Teacher::setScore(Student &s, int score);
    };
    
    Student::Student(string name, int age)
    {
        this->name = name;
        this->age = age;
        score = 0;
    }
    
    void Student::disp()
    {
        cout << "I am a student!" << endl;
        cout << name << " " << age << " " << score << endl;
    }
    
    class Teacher
    {
        string name;
        int age;
    public:
        Teacher(){};
        Teacher(string name="onname", int age=30);
        void disp();
        // 爲了改變學對象的成績,使用引用類型
        void setScore(Student &s, int score); 
    };
    
    Teacher::Teacher(string name, int age)
    {
        this->name = name;
        this->age = age;
    }
    
    void Teacher::disp()
    {
        cout << "I am a teacher!" << endl;
        cout << name << " " << age << endl;
    }
    
    // 因要訪問別的類對象的私有成員,需定義友元函數
    void Teacher::setScore(Student &s, int score)
    {
        s.score = score; 
    }
    
    int main()
    {
        Teacher t = Teacher("Jack");
        t.disp();
        Student s = Student("Mary", 19);
        s.disp();
        // 老師修改學生成績
        t.setScore(s,90);
        t.disp();
        return 0;
    }
    
No.3
  • 說明: 一個類中的一個對象想訪問同類中的另一個對象的私有成員,可直接訪問
  • 舉例
    #include<iostream>
    using namespace std;
    
    class Complex
    {
    private:
        int real, imag;
    public:
        Complex(int r = 0, int i = 0);
        void disp();
        void input();
        Complex operator+(Complex c);
    };
    
    Complex::Complex(int r, int i)
    {
        this->real = r;
        this->imag = i;
    }
    
    void Complex::disp()
    {
        cout << real << " " << imag << endl;
    }
    
    Complex Complex::operator+(Complex c)
    {
        // 直接用傳入對象的私有屬性,將它們實部和虛部分別相加後再利用構造函數創建新對象返回
        return Complex(real+c.real,imag + c.imag);
    }
    int main()
    {
    
        Complex c1(2,3), c2(2,-3), c3;
        c3.disp()
        c3 = c1 + c2;
        c3.disp();
        return 0;
    }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章