### 友元类和友元方法

对于类的私有方法，只有在该类中允许访问，其他类是不能访问的。但在开发程序时，如果两个类的耦合度比较紧密，能够在一个类中访问另一个类的私有成员会带来很大的方便。C++语言提供了友元类和友元方法（或者称为友元函数）来实现访问其他类的私有成员。当用户希望另一个类能够访问当前类的私有成员时，可以在当前类中将另一个类作为自己的友元类，这样，在另一个类中就可以访问当前类的私有成员了。

例如，定义友元类。

class CItem //定义一个 CItem 类

{

private:

char m_Name[128]; //定义私有的数据成员

void OutputName() //定义私有的成员函数

{

printf("%s\n",m_Name); //输出 m_Name

}

public:

friend class CList; //将 CList 类作为自己的友元类

void SetItemName(const char* pchData) //定义共有成员函数，设置 m_Name 成员

{

if (pchData != NULL) //判断指针是否为空

{

strcpy(m_Name,pchData); //赋值字符串

}

}

CItem() //构造函数

{

memset(m_Name,0,128); //初始化数据成员 m_Name

}

};

class CList //定义类 CList

{

private:

CItem m_Item; //定义私有的数据成员 m_Item

public:

void OutputItem(); //定义共有成员函数

};

void CList::OutputItem() //OutputItem 函数的实现代码

{

m_Item.SetItemName("BeiJing"); //调用 CItem 类的共有方法

m_Item.OutputName(); //调用 CItem 类的私有方法

}

上述代码中，在定义 CItem 类时，使用 friend 关键字将 CList 类定义为 CItem 类的友元，这样 CList 类中的所有方法都可以访问 CItem 类中的私有成员了。在 CList 类的 OutputItem 方法中，语句“m_Item.OutputName()”演示了调用 CItem 类的私有方法 OutputName。

在开发程序时，有时需要控制另一个类对当前类的私有成员的访问。例如，假设需要实现只允许 CList 类的某个成员访问 CItem 类的私有成员，而不允许其他成员函数访问 CItem 类的私有数据。这可以通过定义友元函数来实现。在定义 CItem 类时，可以将 CList 类的某个方法定义为友元方法，这样就限制了只有该方法允许访问 CItem 类的私有成员。

例如，定义友元方法。

class CItem; //前导声明 CItem 类

class CList //定义 CList 类

{

private:

CItem * m_pItem; //定义私有数据成员 m_pItem

public:

CList(); //定义默认构造函数

~CList(); //定义析构函数

void OutputItem(); //定义 OutputItem 成员函数

};

class CItem //定义 CItem 类

{

friend void CList::OutputItem(); //声明友元函数

private:

char m_Name[128]; //定义私有数据成员

void OutputName() //定义私有成员函数

{

printf("%s\n",m_Name); //输出数据成员信息

}

public:

void SetItemName(const char* pchData) //定义共有方法

{

if (pchData != NULL) //判断指针是否为空

{

strcpy(m_Name,pchData); //赋值字符串

}

}

CItem() //构造函数

{

memset(m_Name,0,128); //初始化数据成员 m_Name

}

};

void CList::OutputItem() //CList 类的 OutputItem 成员函数的实现

{

m_pItem->SetItemName("BeiJing"); //调用 CItem 类的共有方法

m_pItem->OutputName(); //在友元函数中访问 CItem 类的私有方法 OutputName

}

CList::CList() //CList 类的默认构造函数

{

m_pItem = new CItem(); //构造 m_pItem 对象

}

CList::~CList() //CList 类的析构函数

{

delete m_pItem; //释放 m_pItem 对象

m_pItem = NULL; //将 m_pItem 对象设置为空

}

int main(int argc, char* argv[]) //主函数

{

CList list; //定义 CList 对象 list

list.OutputItem(); //调用 CList 的 OutputItem 方法

return 0;

}

上述代码中，在定义 CItem 类时，使用 friend 关键字将 CList 类的 OutputItem 方法设置为友元函数，在 CList 类的 OutputItem 方法中访问了 CItem 类的私有方法 OutputName。执行上述代码，效果如图 1 所示。

图 1 友元函数

对于友元函数来说，不仅可以是类的成员函数，还可以是一个全局函数。下面的代码在定义 CItem 类时，将一个全局函数定义为友元函数，这样在全局函数中就可以访问 CItem 类的私有成员了。

其程序代码如下：

class CItem //定义 CItem 类

{

friend void OutputItem(CItem *pItem); //将全局函数 OutputItem 定义为友元函数

private:

char m_Name[128]; //定义数据成员

void OutputName() //定义私有方法

{

printf("%s\n",m_Name); //输出信息

}

public:

void SetItemName(const char* pchData) //定义共有方法

{

if (pchData != NULL) //判断指针是否为空

{

strcpy(m_Name,pchData); //赋值字符串

}

}

CItem() //定义构造函数

{

memset(m_Name,0,128); //初始化数据成员

}

};

void OutputItem(CItem *pItem) //定义全局函数

{

if (pItem != NULL) //判断参数是否为空

{

pItem->SetItemName("同一个世界，同一个梦想\n"); //调用 CItem 类的共有方法

pItem->OutputName(); //调用 CItem 类的私有方法

}

}

int main(int argc, char* argv[]) //主函数

{

CItem Item; //定义一个 CItem 类对象 Item

OutputItem(&Item); //通过全局函数访问 CItem 类的私有方法

return 0;

}

执行上述代码，效果如图 2 所示。

图 2 全局友元函数