[C++] 友元(friends)

友元声明只能出现在类定义内部,在类中的位置不限。由于友元非给予访问权限的类的成员,因此不受public, protected, private关键字的制约。[一般而言,友元最好放在类定义的开头,或结尾处]

友元可以是普通函数,可以是另一个类的成员函数,或者是整个类

友元类

如果一个类成为友元类,那么此类的所有成员函数都将成为成员函数。
友元类的最一般的写法:

class B;
class A
{
   // class B 是 class A 的友元类
   friend class B;
   //... .. ...
}
class B
{
   //... .. ...
}

例 1,C++ Primer 上的例子:

class Screen {
    // Window_Mgr members can access private parts of class Screen
    friend class Window_Mgr;
public:
    typedef std::string::size_type index;
    // return character at the cursor or at a given position
    char get() const { return contents[cursor]; }
    char get(index ht, index wd) const;
    // remaining members
private:
    std::string contents;
    index cursor;
    index height, width;
};

以上, Window_MgrScreen的友元,Window_Mgr的成员函数因此能直接访问Screen类的私有成员,例如,Window_Mgr可以有如下的重定位函数:

Window_Mgr& Window_Mgr::relocate(Screen::index r, Screen::index c, Screen& s)
{
    // ok to refer to height and width
    s.height += r;
    s.width += c;
    return *this;
}

例 2, MSDN上的友元类的例子:

// classes_as_friends2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

class YourClass {
friend class YourOtherClass;  // Declare a friend class
public:
   YourClass() : topSecret(0){}
   void printMember() { cout << topSecret << endl; }
private:
   int topSecret;
};

class YourOtherClass {
public:
   void change( YourClass& yc, int x ){yc.topSecret = x;}
};

int main() {
   YourClass yc1;
   YourOtherClass yoc1;
   yc1.printMember();
   yoc1.change( yc1, 5 );
   yc1.printMember();
}

例 3, 同时包含友元函数和友元类:

class Rectangle
{
public:
    //constructor, destructor and all that jazz
    friend class Puzzle;
    friend float CalculateArea();
private:
    //rectangle's private data
};

class Puzzle
{
    //normal class stuff
};

float CalculateArea()
{
    //do some fancy calculations
    //return result
}

例 4:

#include <iostream>
using namespace std;

class Square;
class Rectangle {
    int width, height;
public:
    Rectangle(int w = 1, int h = 1):width(w),height(h){} 
    void display() {
        cout << "Rectangle: " << width * height << endl;
    };
    void morph(Square &);
};
class Square {
    int side;
public:
    Square(int s = 1):side(s){} 
    void display() {
        cout << "Square: " << side * side << endl;
    };
    friend class Rectangle;
};
void Rectangle::morph(Square &s) {
    width = s.side;
    height = s.side;
}
int main () {
    Rectangle rec(5,10);
    Square sq(5);
    cout << "Before:" << endl;
    rec.display();
    sq.display();
    rec.morph(sq);
    cout << "\nAfter:" << endl;
    rec.display();
    sq.display();
    return 0;
}

友元函数

一般函数为友元,例 1

这个例子看似相当简单,比C++ Primer上的描述简单多了:

/* C++ program to demonstrate the working of friend function.*/
#include <iostream>
using namespace std;
class Distance
{
    private:
        int meter;
    public:
        Distance(): meter(0) { }
        //friend function
        friend int addFive(Distance);   // 友元函数
};
// friend function definition
int addFive(Distance d)
{
    //accessing private data from non-member function
    d.meter += 5;
    return d.meter;
}
int main()
{
    Distance D;
    cout<<"Distance: "<< addFive(D);
    return 0;
}

输出:

Distance: 5

这个例子实际用处不大,当需要同时操作两个不同类的对象时,友元函数就非常有用。当然,不用友元函数也是可以实现的,但代码会比较长,复杂,难以理解。

一般函数为友元,例 2

将两个不同类的成员相加,这个例子比较有意义:

#include <iostream>
using namespace std;

// forward declaration
class B;
class A {
    private:
      int numA;
    public:
      A(): numA(12) { }
      // 友元函数声明
      friend int add(A, B);
};

class B {
    private:
       int numB;
    public:
       B(): numB(1) { }
       // 友元函数声明
       friend int add(A , B);
};

// Function add() is the friend function of classes A and B
// that accesses the member variables numA and numB
int add(A objectA, B objectB)
{
   return (objectA.numA + objectB.numB);
}

int main()
{
    A objectA;
    B objectB;
    cout<<"Sum: "<< add(objectA, objectB);
    return 0;
}

输出:

扫描二维码关注公众号,回复: 2419334 查看本文章
Sum: 13

一般函数为友元,例 3

MSDN上的:

// friend_functions.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;
class Point
{
    friend void ChangePrivate( Point & );
public:
    Point( void ) : m_i(0) {}
    void PrintPrivate( void ){cout << m_i << endl; }

private:
    int m_i;
};

void ChangePrivate ( Point &i ) { i.m_i++; }

int main()
{
   Point sPoint;
   sPoint.PrintPrivate();
   ChangePrivate(sPoint);
   sPoint.PrintPrivate();
}

输出:

0
1

一般函数为友元,例 4

cpluscplus forum上的例子, 包含操作符重载:

#include <iostream>
using namespace std;

class Number
{   
    friend void Reset(Number &t);
private:
    int num;
    int twiceNum;

public:
    Number(int n = 0);
    Number(const Number & n);
    void setNum(int n);
    void setTwiceNum(int tn);
    int getNum() const;
    int getTwiceNum() const;
    Number operator+ (const Number & r);
    Number operator++ ();
    Number operator++ (int);
};
Number::Number(int n = 0)
{
    setNum(n);
}
Number::Number(const Number & n)
{
    setNum(num = 0 & twiceNum);
}
void Number::setNum(int n)
{
    n = num;
    twiceNum = 2 * num;
}
void Number::setTwiceNum(int tn)
{
    if (tn % 2 == 0)
    {
        tn = twiceNum;
    }
    else
    {
        twiceNum = 0;
    }
    num = twiceNum / 2;
}
int Number::getNum() const
{
    return num;
}
int Number::getTwiceNum() const
{
    return twiceNum;
}
Number Number::operator+ (const Number & r)
{
    /*r;
    setNum;
    return 0;*/
}
Number Number::operator++ ()
{
    /*num = num += 1;
    setNum;*/
}
Number Number::operator++ (int)
{
    /*num = num + 1;
    setNum;*/
}
friend void Number::Reset(Number &t)   //friend
{
    Number::num = 0;
    Number::twiceNum = 0;
}
int main()
{
    Number a, b(5), c(10);
    Number d=c;
    Number e;
    cout<<"a: " <<a.getNum() << ", 2 X a: "<<a.getTwiceNum()<<endl;
    cout<<"b: " <<b.getNum() << ", 2 X b: "<<b.getTwiceNum()<<endl;
    cout<<"c: " <<c.getNum() << ", 2 X c: "<<c.getTwiceNum()<<endl;
    cout<<"d: " <<d.getNum() << ", 2 X d: "<<d.getTwiceNum()<<endl;
    cout <<endl;
    Reset(b);
    cout <<"After reset of b"<<endl;
    cout<<"b: " <<b.getNum() << ", 2 X b: "<<b.getTwiceNum()<<endl;
    cout <<endl;
    b.setNum(7);
    cout <<"After b.setNum(7)"<<endl;
    cout<<"b: " <<b.getNum() << ", 2 X b: "<<b.getTwiceNum()<<endl;
    cout <<endl;
    b.setTwiceNum(21);
    cout <<"After b.setTwiceNum(21)"<<endl;
    cout<<"b: " <<b.getNum() << ", 2 X b: "<<b.getTwiceNum()<<endl;
    cout <<endl;
    b.setTwiceNum(30);
    cout <<"After b.setTwiceNum(30)"<<endl;
    cout<<"b: " <<b.getNum() << ", 2 X b: "<<b.getTwiceNum()<<endl;
    cout <<endl;
    a= b + c;
    cout <<"After a= b+c"<<endl;
    cout<<"a: " <<a.getNum() << ", 2 X a: "<<a.getTwiceNum()<<endl;
    cout<<"b: " <<b.getNum() << ", 2 X b: "<<b.getTwiceNum()<<endl;
    cout<<"c: " <<c.getNum() << ", 2 X c: "<<c.getTwiceNum()<<endl;
    cout <<endl;
    e= ++a;
    cout <<"After e= ++a"<<endl;
    cout<<"a: " <<a.getNum() << ", 2 X a: "<<a.getTwiceNum()<<endl;
    cout<<"e: " <<e.getNum() << ", 2 X e: "<<e.getTwiceNum()<<endl;
    cout <<endl;
    e= a++;
    cout <<"After e= a++"<<endl;
    cout<<"a: " <<a.getNum() << ", 2 X a: "<<a.getTwiceNum()<<endl;
    cout<<"e: " <<e.getNum() << ", 2 X e: "<<e.getTwiceNum()<<endl;
    cout <<endl;
    return 0;
}

一般函数为友元,例 5

#include <iostream>
using namespace std;

class Rectangle {
    int width, height;

public:
    Rectangle(int w = 1, int h = 1):width(w),height(h){} 
    friend void display(Rectangle &);
};

void display(Rectangle &r) {
    cout << r.width * r.height << endl;
}

int main () {
    Rectangle rect(5,10);
    display(rect);
    return 0;
}

一般函数为友元,例 6

#include <iostream>
using namespace std;

class Square;  // forward declaration
class Rectangle {
    int width, height;
public:
    Rectangle(int w = 1, int h = 1):width(w),height(h){} 
    friend void display(Rectangle &, Square &);
};
class Square {
    int side;
public:
    Square(int s = 1):side(s){} 
    friend void display(Rectangle &, Square &);
};
void display(Rectangle &r, Square &s) {
    cout << "Rectangle: " << r.width * r.height << endl;
    cout << "Square: " << s.side * s.side << endl;
}
int main () {
    Rectangle rec(5,10);
    Square sq(5);
    display(rec,sq);
    return 0;
}

输出:

Rectangle: 50
Square: 25

类成员函数声明为友元:

声明成员函数为友元时,函数名必须用其所属的类名修饰:

class Screen {
    // Window_Mgrmust be defined before class Screen
    friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index, Window_Mgr::index, Screen&);
    // ...restofthe Screen class
};

例子:

// classes_as_friends1.cpp
// compile with: /c
class B;
class A {
public:
   int Func1( B& b );
private:
   int Func2( B& b );
};
class B {
private:
   int _b;
   // A::Func1 is a friend function to class B
   // so A::Func1 has access to all members of B
   friend int A::Func1( B& );
};
int A::Func1( B& b ) { return b._b; }   // OK
int A::Func2( B& b ) { return b._b; }   // C2248

[1] C++ Primer 12.5
[2] C++ friend Function and friend Classes (百度快照)
[3] https://msdn.microsoft.com/zh-cn/magazine/h2x4fzdz(v=vs.110)
[4] http://www.cplusplus.com/forum/general/86722/
[5] http://www.bogotobogo.com/cplusplus/friendclass.php

猜你喜欢

转载自blog.csdn.net/ftell/article/details/81080301
今日推荐