在C++中,friend是破壞封裝性的,friend 的在C++文法體系是一個比較小的知識點,在開發中用的也不是很多。friend 的用法有時很容易忘記,一些陷阱經常跳進去。本文做了一個簡短總結。
C++中的友元機制允許類的非公有成員被一個類或者函數通路,友元按類型分為三種:普通非類成員函數作為友元,類的成員函數作為友元,類作為友元。友元包括友元的聲明以及友元的定義。友元的聲明預設為了extern,就是說友元類或者友元函數的作用域已經擴充到了包含該類定義的作用域,是以即便我們在類的内部定義友元函數也是沒有關系的。
1.普通的非成員函數友元
這類友元函數最常見,通常是操作符,例如輸入輸出操作符,示例如下所示:
//OpeClass.h
#pragma once
class OpeClass
{
friend OpeClass& operator <<(const OpeClass& xx);
public:
OpeClass(void);
OpeClass(int x,int y);
~OpeClass(void);
private:
int width;
int height;
};
//OpeClass.cpp
#include "OpeClass.h"
OpeClass::OpeClass(void)
{
width = 50;
height = 50;
}
OpeClass::OpeClass(int x,int y):width(x),height(y)
{
}
OpeClass::~OpeClass(void)
{
}
OpeClass& operator<<(const OpeClass& xx)
{
cout<<xx.width<<xx.height;
return *this;
}
2.類作為友元
類作為友元需要注意的是友元類和原始類之間的互相依賴關系,如果在友元類中定義的函數使用到了原始類的私有變量,那麼就需要在友元類定義的檔案中包含原始類定義的頭檔案。但是在原始類的定義中(包含友元類聲明的那個類),就不需要包含友元類的頭檔案.
另外,不需要在類定義前去聲明友元類,因為友元類的聲明自身就是一種聲明。
//A.h
#pragma once
#include <iostream>
using namespace std;
class A
{
//friend class B; //如果不寫這句話将會出現編譯錯誤
public:
~A(void);
A();
private:
int m_nItem;
};
//A.cpp
#include "A.h"
A::A()
{
m_nItem =3;
}
A::~A(void)
{
}
//B.h
#pragma once
class B
{
public:
B(void);
~B(void);
int func();
};
//B.cpp
#include "StdAfx.h"
#include "B.h"
#include "A.h" //must include A.h
#include <iostream>
B::B(void)
{
}
B::~B(void)
{
}
int B::func()
{
cout<<"This is in B"<<endl;
A a;
return a.m_nItem;
}
3.類成員函數作為友元函數
這個稍微有點複雜,因為你要類成員函數作為友元,你在聲明友元的時候要用類限定符,是以必須先定義包含友元函數的類,但是在定義友元的函數時候,又必須事先定義原始類。通常的做法先定義包含友元函數的類,再定義原始類,這個順序不能亂。(如果是友元類,則沒有這種這種必須)如下面所示:
//A.h
#pragma once
#include "B.h"
class A
{
friend int B::func(A xx);
public:
A(void):mx(20),my(30){}
~A(void){}
private:
int mx;
int my;
};
//B.h
#pragma once
class A;
class B
{
public:
B(void);
~B(void);
int func(A xx);
};
//B.cpp
#include "B.h"
#include "A.h"
B::B(void)
{
}
B::~B(void)
{
}
int B::func(A xx)
{
return xx.mx * xx.my;
}
//main.cpp
#include "A.h"
#include "B.h"
#include <iostream>
using namespace std;
void main()
{
A a;
B b;
cout<<b.func(a)<<endl;
system("pause");
}
4. 友元不具有互相性,隻具有單項性
若類B是類A的友元,類A不一定是類B的友元,要看在類中是否有相應的聲明。
5. 友元不能被繼承
B是A的友元類,C是B的子類,推不出C是A的友元
6. 友元不具有傳遞性
B是A的友元,C是B的友元,推不出C是A的友元
7. 友元函數的使用技巧
在用C++實作單例模式時,可以利用友元函數執行個體化對象。然後把類的構造函數和析構函數都設計成私有函數。
class CMySingleton
{
public:
friend CMySingleton& InstanceMEC();
private:
CMySingleton() {};
CMySingleton(const CMySingleton &lxSington) {};
~CMySingleton(){};
};
CMySingleton& InstanceMEC()
{
//因為函數InstanceMEC()是類ClxSingletonMEC的友元函數,是以可以通路類所有的成員函數.是以不會有編譯錯誤
static CMySingleton Instance;
return Instance;
}