C++中的友元函数和友元类
1.友元:
问题:无论使用何种继承,子类都是无法使用父类的私有成员
解决: C++提供了一种机制,A类的内部可以直接使用B类的私有成员(还是要用B类的对象调用私有成员) —》友元类
普通函数的内部可以直接使用某个类的私有成员 —》友元函数
2.友元的语法规则
2.1 友元函数
分为两种情况:
- 普通函数作为类的友元函数
- 成员函数作为类的友元函数(写法比较复杂)
friend 返回值 函数名(参数);
示例代码:普通函数作为类的友元函数
#include <iostream>
using namespace std;
/*
友元函数:分为两种
第一种:普通函数作为类的友元函数
*/
class Cat
{
public:
Cat(string &name,int age) : m_name(name),m_age(age)
{
cout<<"猫构造"<<endl;
}
~Cat()
{
cout<<"猫析构"<<endl;
}
friend void show(Cat *c);
private:
string m_name;
int m_age;
};
void show(Cat *c)
{
// 若不声明为友元函数时报错error: ‘std::string Cat::m_name’ is private within this context
cout<<"name="<<c->m_name<<endl;
cout<<"age="<<c->m_age<<endl;
}
int main()
{
string name="Tom";
Cat *c1=new Cat(name, 2);
// 报错:error: cannot bind non-const lvalue reference of type ‘std::string&’
Cat c2("Jerry", 3);
show(c1);
}
/*
执行结果:
猫构造
name=Tom
age=2
*/
示例代码:成员函数作为类的友元函数
#include <iostream>
using namespace std;
/*
友元函数:
成员函数作为类的友元函数
Dog有个成员函数,该成员函数想要访问/修改猫的私有成员变量
*/
//前向引用声明:告诉编译器有定义Cat这个类
//前向引用声明的缺陷:只能告知Cat类的存在,但是这个类具体有什么成员无法得知
class Cat;
class Dog
{
public:
Dog()
{
cout<<"狗构造"<<endl;
}
~Dog()
{
cout<<"狗析构"<<endl;
}
void show(Cat &c);
};
class Cat
{
public:
Cat(string &name,int age)
{
m_name=name;
m_age=age;
cout<<"猫构造"<<endl;
}
~Cat()
{
cout<<"猫析构"<<endl;
}
friend void Dog::show(Cat &c); // 声明为友元函数
private:
string m_name;
int m_age;
};
void Dog::show(Cat &c) // 定义为友元函数,可以访问Cat类的私有成员
{
cout<<"name="<<c.m_name<<endl;
cout<<"age="<<c.m_age<<endl;
}
int main()
{
string name = "小猫";
Cat c(name,10);
Dog d;
d.show(c);
}
/*
执行结果:
猫构造
狗构造
name=小猫
age=10
狗析构
猫析构
*/
2.2 友元类
friend class 类名;
示例代码:友元类-某个类整体作为另外一个类的友元
#include <iostream>
using namespace std;
/*
友元类:某个类整体作为另外一个类的友元
*/
class Dog;
class Cat
{
public:
Cat(string &name,int age)
{
m_name=name;
m_age=age;
cout<<"猫构造"<<endl;
}
~Cat()
{
cout<<"猫析构"<<endl;
}
//声明狗这个类是猫的友元类(狗类要访问或修改猫的私有成员要猫承认是狗的"朋友")
friend class Dog;
private:
string m_name;
int m_age;
};
class Dog
{
public:
Dog()
{
cout<<"狗构造"<<endl;
}
~Dog()
{
cout<<"狗析构"<<endl;
}
//狗里面的成员方法访问猫的私有成员
void show(Cat &c)
{
cout<<"name="<<c.m_name<<endl;
cout<<"age="<<c.m_age<<endl;
}
//狗里面的成员方法修改猫的私有成员
void setCat(Cat &c, string &newname,int newage)
{
c.m_name=newname;
c.m_age=newage;
}
};
int main()
{
string name = "小猫";
string newname = "大猫";
Cat c(name,10);
Dog d;
//狗里面的成员方法访问猫的私有成员
d.show(c);
//狗里面的成员方法修改猫的私有成员
d.setCat(c,newname,20);
d.show(c);
}
/*
执行结果:
猫构造
狗构造
name=小猫
age=10
name=大猫
age=20
狗析构
猫析构
*/
3.特点
- 友元不能继承,A是B的友元类,但是A的子类并不是B的友元类
- 友元是单向的,A是B的友元,但是不能反过来
- 友元不能传递,A是B的友元,B是C的友元,不能得出结论A是C的友元
缺点:
\quad 破坏了类的封装性
示例代码:普通函数作为类的友元函数写在类的里面
#include <iostream>
using namespace std;
/*
普通函数的代码写在类的里面
*/
class Cat
{
public:
Cat(string _name,int _age)
{
name=_name;
age=_age;
}
//声明show函数是猫的友元函数
friend void show(Cat &other) //代码写在类的里面,是可以的,但是show依然是个普通函数
{
cout<<"猫的姓名: "<<other.name<<endl;
cout<<"猫的年龄: "<<other.age<<endl;
}
private:
int age;
string name;
};
int main()
{
Cat c1("旺财",5);
show(c1);
}