友元
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元函数
声明友元函数
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。 格式如下:
class Myclass
{
public:
……
friend void add(int n );
……
}
友元函数的特点:
友元函数可以使一个普通的函数,也可以是其他类的函数,但它一定不是本类的成员函数。 一般成员函数只可以访问一个类的私有和保护的成员,但友元函数可以访问多个类的私有和保护函数。 友元函数可以绕过成员函数,直接访问类的私有和保护函数,这样就避免了调用成员函数相关的开销。 如果没有友元功能,一个函数要想访问某个类的私有和保护的成员时,只能是将这个成员设置为公共的,这样一来用户就可以访问该类中的所有成员,从而破坏了信息的隐蔽性。 由于友元函数不是本类的成员函数。其定义和调用方式与普通函数一样,在调用友元函数时不需要使用“ · ”运算符,在定义时不需要实用类前缀。 友元函数并不是类的成员函数,他不带有this指针。所以必须用对象名或对象的引用作为友元函数的形参,并在函数体内使用运算符“.”来访问对象的成员。 由于友元函数可使用类里面的所有成员,从而破坏数据的安全性,所以使用友元函数必须谨慎,不要通过友元函数对数据成员进行危险的操作。
例:
//编写一个函数,以友元函数的方式计算一个点到一条直线的距离
#include<iostream>
#include<math.h>
using namespace std;
class Point
{
public:
Point(int x1, int y1){ x = x1; y = y1; }
int x, y;
};
class Line//线类
{
int a, b, c;
public:
Line(int a1, int b1, int c1){ a = a1; b = b1; c = c1; }
friend double dist(Line l, Point p)
{
double d;
d = abs(l.a*p.x + l.b*p.y + l.c) / (sqrt(l.a*l.a + l.b*l.b));
return d;
}
};
void main()
{
Point p(10, 10);
Line l(2, 4, -3);
cout << "d=" << dist(l, p) << endl;
system("pause");
}
友元类
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
友元关系是单向的,不具有交换性。比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。 友元关系不能传递 如果B是A的友元,C是B的友元,则不能说明C时A的友元。
例:编写一个程序,实现栈的压入和弹出。其中有两个类:一个是结点类Node,它包含结点值data和指向下一个节点next,另一个类是栈Stack,它包含头指针top。
#include<iostream>
using namespace std;
class Stack;
class Node
{
int data;
Node *next;
public:
Node(int d)
{
data = d;
next = NULL;
}
friend class Stack;
};
class Stack
{
Node *top;
public:
Stack()
{
top = NULL;
}
void push(int d)
{
Node *p = new Node(d);
if (top != NULL)
p->next = top;
top = p;
}
int pop(int &c)
{
Node *p = top;
if (top != NULL)
{
c = p->data;
top = top->next;
delete p;
return 1;
}
else return 0;
}
};
void main()
{
Stack s;
int c;
s.push(1);
s.push(2);
s.push(3);
s.push(4);
cout << "出栈次序:";
while (s.pop(c))
cout << c << " ";
cout << endl;
system("pause");
}
- Oracle 索引
- Oracle dbms_random随机函数包
- volatile和Synchronized区别
- Oracle 快速插入1000万条数据的实现方式
- HashMap实现原理分析
- Oracle TM锁和TX锁
- Oracle给Select结果集加锁,Skip Locked(跳过加锁行获得可以加锁的结果集)
- select for update和select for update wait和select for update nowait的区别
- Android入门之动画
- Java 读写大文本文件
- 高级聚类
- Oracle 数据库名、实例名、Oracle_SID
- Oracle 多行、多列子查询
- Android入门介绍
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- JUC学习之8锁现象
- TensorFlow惊现大bug?网友:这是逼着我们用PyTorch啊!
- 机器学习|用Q-Learning走迷宫
- C++设计模式笔记(03-02) - Template Method_模板方法(下)
- 从零开始学习华为路由交换 | OSPF修改计时器
- 【没落的985/211】Python爬取知乎8万字回答进行高校分析
- LinkedBlockingQueue源码学习
- 三歪吐血总结了各个中间件是如何实现持久化的
- ThreadPoolExecutor源码学习
- Docker六脉神剑(四) 使用Docker-Compose进行服务编排搭建lnmp环境
- 干的想喝水,一篇文章带你读懂硬盘工作原理!
- 微信小程序开发实战(11):滚动组件(picker)
- Docker六脉神剑 (五) Docker Swarm集群搭建及基础服务部署
- 思科模拟器GNS3将路由器变成交换机的方法
- docker安装nginx并配置https