简言
C++的三大特性之一封装性要求基本上大部分数据成员都应该定义成私有成员,不允许被类的外部所访问,而友元的存在就是为了让外部能够访问到类的私有成员。
全局函数做友元
我们可以定义类的成员函数,也可以定义全局函数,尽管全局函数是类的接口的一部分,但是它们都不是类的成员。类可以允许其他类或函数访问他们的非公有成员,方法是令其它类或函数成为它的友元,只需要在全局函数的声明前加上friend就可以了。
友元申明只能出现在类的内部,但是具体的位置不限,一般都是在类定义开始的地方集中声明。
#pragma once
#include <iostream>
class Animal
{
friend std::istream& insert(std::istream& is, Animal& animal);
friend std::ostream& output(std::ostream& io, const Animal& animal);
public:
Animal(int a) :foodCount(a) {}
int getAge() const { return age; }
int getHigh() const { return high; }
int getWeight() const { return weight; }
void eat();
private:
int age;
int high;
int weight;
int foodCount;
};
#include "Animal.h"
void Animal::eat()
{
--foodCount;
}
std::istream& insert(std::istream & is, Animal & animal)
{
is >> animal.foodCount;
return is;
}
std::ostream& output(std::ostream & io, const Animal & animal)
{
io << animal.foodCount;
return io;
}
类做友元
比如说当我们在Animal中需要访问Clothes类的非公有成员变量,那么我们就可以把Animal定义成Clothes的友元类。一旦定义成了友元类之后,那么Animal就可以访问Clothes类的所有成员包括非公有成员。
Clothes类
#pragma once
class Clothes
{
friend class Animal;
public:
Clothes(int a = 5,int b = 10):width(a),length(b) {}
int getSize() const { return size; }
void setSize(int s) { size = s; }
private:
int width;
int size;
int length;
};
Animal类
#pragma once
#include <iostream>
#include "Clothes.h"
class Animal
{
friend std::istream& insert(std::istream& is, Animal& animal);
friend std::ostream& output(std::ostream& io, const Animal& animal);
public:
Animal(int a) :foodCount(a) {}
int getAge() const { return age; }
int getHigh() const { return high; }
int getWeight() const { return weight; }
void getClothes(Clothes& clothes);
void eat();
private:
Clothes m_clothes;
int age;
int high;
int weight;
int foodCount;
};
#include "Animal.h"
void Animal::getClothes(Clothes & clothes)
{
clothes.setSize(clothes.length*clothes.width);
}
void Animal::eat()
{
--foodCount;
}
std::istream& insert(std::istream & is, Animal & animal)
{
is >> animal.foodCount;
return is;
}
std::ostream& output(std::ostream & io, const Animal & animal)
{
io << animal.foodCount;
return io;
}
main函数
#include "Clothes.h"
#include "Animal.h"
int main()
{
Clothes clothes(10, 20);
Animal pig(5);
pig.getClothes(clothes);
std::cout << clothes.getSize();
}
类的成员函数做友元
类的成员函数做友元就是允许一个类的某个成员函数访问其他类的非公有成员。
Toy类
#pragma once
#include "Animal.h"
class Toy
{
friend void Animal::palyToy(Toy* toy);
public:
Toy(int a = 10):size(a) {}
int getSize() const { return size; }
private:
int size;
};
Animal类
#pragma once
#include <iostream>
#include "Clothes.h"
class Toy;
class Animal
{
friend std::istream& insert(std::istream& is, Animal& animal);
friend std::ostream& output(std::ostream& io, const Animal& animal);
public:
Animal(int a) :foodCount(a) {}
int getAge() const { return age; }
int getHigh() const { return high; }
int getWeight() const { return weight; }
void getClothes(Clothes& clothes);
void eat();
void palyToy(Toy* toy);
private:
Clothes m_clothes;
int age;
int high;
int weight;
int foodCount;
};
#include "Animal.h"
#include "Toy.h"
void Animal::getClothes(Clothes & clothes)
{
clothes.setSize(clothes.length*clothes.width);
}
void Animal::eat()
{
--foodCount;
}
void Animal::palyToy(Toy* toy)
{
std::cout << toy->size;
}
std::istream& insert(std::istream & is, Animal & animal)
{
is >> animal.foodCount;
return is;
}
std::ostream& output(std::ostream & io, const Animal & animal)
{
io << animal.foodCount;
return io;
}
总结:
友元虽然可以是其他函数或者类可以访问非公有成员,但是这个也在一定程度上破坏了类的封装性。