<C++略识>之友元

C++有了类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,以此提供类与外界的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该类的友元函数。除了友元函数外,还有友元类,两者统称为友元。

友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。

友元函数:

  1. 为什么要使用友元函数?
    在实现类之间数据共享时,减少系统开销,提高效率。如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数。具体来说:为了使其他类的成员函数直接访问该类的私有变量。即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数。实际上具体大概有下面两种情况需要使用友元函数:
    (1)运算符重载的某些场合需要使用友元。(2)两个类要共享数据的时候。

  2. 友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。(我的习惯是一般放在类开始的地方)

  3. 友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下: friend 类型函数名(形式参数);

  4. 一个函数可以是多个类的友元函数,只需要在各个类中分别声明。

友元类:

  1. 友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。

  2. 当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:friend class 类名;其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。
    例如,以下语句说明类B是类A的友元类:

class A
{
    friend class B;
public:
    // to do..
};

经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。

使用友元类时注意:

(1) 友元关系不能被继承。

(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。

(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明

下面看看友元的几种情况

1. 将全局函数声明为友元函数

#include<iostream>
#include<string>
using namespace std;

class Student
{
    friend void display(Student &);  //将全局函数display声明为Student类的友元函数
public:
    Student(string name, int age, int score);
private:
    string m_strName;
    int m_iAge;
    int m_iScore;
};
Student::Student(string name, int age, int score)
{
    m_strName = name;
    m_iAge = age;
    m_iScore = score;

}

//普通全局函数
void display(Student &stu)
{
    cout<<stu.m_strName<<"的年龄是 "<<stu.m_iAge<<",成绩是 "<<stu.m_iScore<<endl;
}

int main()
{
    Studentstu("小明", 16, 95);
    display(stu);
    system("pause");
    return 0;
}

运行结果: 小明的年龄是 16,成绩是 95

2. 将其他类的成员函数声明为友元函数

#include<iostream>
#include<string>
using namespace std;

class Address; //对Address类的提前引用声明

class Student//声明Student类
{
public:
    Student(string name, int age, int score);
    void display(Address &); //这里的display函数参数是Address类型,所以开头要提前引用声明
private:
    string m_strName;
    int m_iAge;
    int m_iScore;
};

class Address//声明Address类
{
    friend void Student::display(Address &); //将Student类中的成员函数display声明为友元函数
public:
    Address(string province, string city, string district);
private:
    string m_strProvince; //省
    string m_strCity; //市
    string m_strDistrict; //县

};

Address::Address(string province, string city, string district) //Address构造函数的实现
{
    m_strProvince = province;
    m_strCity = city;
    m_strDistrict = district;
}

Student::Student(string name, int age, int score)  //Student构造函数的实现
{
    m_strName = name;
    m_iAge = age;
    m_iScore = score;

}

void Student::display(Address &add)//Student成员函数的实现
{
    cout<<m_strName<<"的年龄是 "<<m_iAge<<",成绩是 "<<m_iScore<<endl;
    cout<<"家庭住址:"<<add.m_strProvince<<"省"<<add.m_strCity<<"市"<<add.m_strDistrict<<"县"<<endl;
}

int main()
{
    Studentstu("小明", 16, 95);
    Address add("江苏", "扬州", "宝应");
    stu.display(add);
    system("pause");
    return 0;
}

运行结果:
小明的年龄是 16,成绩是 95
家庭住址:江苏省扬州市宝应县

3. 将其他类声明为友元类

#include<iostream>
#include<string>
using namespace std;

class Match;
class Time
{    
    friend Match; //声明Match类为Time类的友元类
public:
    Time(int hour, int min, int sec);
private:
    void printTime(); 
    int m_iHour;
    int m_iMinute;
    int m_iSecond;
};

class Match
{
public:
    Match(int hour, int min, int sec);
    void testTime();
private:
    Time m_tTimer;
}; 

Time::Time(int hour, int min, int sec)
{
    m_iHour = hour;
    m_iMinute = min;
    m_iSecond = sec;
}
void Time::printTime()
{
    cout<<m_iHour<<"时"<<m_iMinute<<"分"<<m_iSecond<<"秒"<<endl;
}


Match::Match(int hour, int min, int sec):m_tTimer(hour, min, sec)//通过初始化列表来实例化m_tTimer的三个参数
{
// to do
}

void Match::testTime()
{
    m_tTimer.printTime(); //访问Time的私有成员函数
    cout<<m_tTimer.m_iHour<<":"<<m_tTimer.m_iMinute<<":"<<m_tTimer.m_iSecond<<endl; //访问Time类的私有数据成员
}

int main()
{
    Matchm(11,20,30);
    m.testTime();

    system("pause");
    return 0;
}

运行结果:
11时20分30秒
11:20:30

注意事项:

  1. 友元可以访问类的私有成员。

  2. 只能出现在类定义内部,友元声明可以在类中的任何地方,一般放在类定义的开始或结尾。

  3. 友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。

  4. 类必须将重载函数集中每一个希望设为友元的函数都声明为友元。

  5. 友元关系不能继承,基类的友元对派生类的成员没有特殊的访问权限。如果基类被授予友元关系,则只有基类具有特殊的访问权限。该基类的派生类不能访问授予友元关系的类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值