友元函数
在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术
类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
友元的目的 就是让一个函数或者类 访问另一个类中的私有成员
如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend,如下所示:
class Box
{
double width;
public:
double length;
friend void printWidth( Box box );
void setWidth( double wid );
};
//全局函数 printWidth,这样Box类外的函数就可以使用Box类里面封装的成员变量了
void printWidth( Box box )
{
//函数体
}
友元函数示例
错误示例
#include <iostream>
using namespace std;
class Box
{
private:
double width;
public:
//friend void printWidth(Box box);
void setWidth(double wid);
};
void Box::setWidth(double wid)
{
width = wid;
}
// 请注意:printWidth() 不是任何类的成员函数
void printWidth(Box box)
{
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
cout << "Width of box : " << box.width << endl;
}
int main()
{
Box box;
box.setWidth(10.0);
printWidth(box);
return 0;
}
修正示例
#include <iostream>
using namespace std;
class Box
{
private:
double width;
public:
friend void printWidth(Box box);
void setWidth(double wid);
};
void Box::setWidth(double wid)
{
width = wid;
}
// 请注意:printWidth() 不是任何类的成员函数
void printWidth(Box box)
{
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
cout << "Width of box : " << box.width << endl;
}
int main()
{
Box box;
box.setWidth(10.0);
printWidth(box);
return 0;
}
问题描述
提示:这里描述项目中遇到的问题:
例如:数据传输过程中数据不时出现丢失的情况,偶尔会丢失一部分数据
APP 中接收数据代码:
@Override
public void run() {
bytes = mmInStream.read(buffer);
mHandler.obtainMessage(READ_DATA, bytes, -1, buffer).sendToTarget();
}
初始化列表
创建一个对象的时候,编译器会调用构造函数给对象中的成员赋初值
#include <iostream>
using namespace std;
class Box
{
private:
double _width;
public:
//构造函数的声明
Box(int width);
friend void printWidth(Box box);
};
//构造函数的定义
Box::Box(int width)
{
_width = width;
}
// 请注意:printWidth() 不是任何类的成员函数
void printWidth(Box box)
{
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
cout << "Width of box : " << box._width << endl;
}
int main()
{
Box box(1010);
printWidth(box);
return 0;
}
但上述赋初值不能称作类对象成员的初始化,因为构造函数体内可以多次赋值:
#include <iostream>
using namespace std;
class Box
{
private:
double _width;
public:
//构造函数的声明
Box(int width);
friend void printWidth(Box box);
};
//构造函数的定义
Box::Box(int width)
{
_width = 123;
_width = width;
_width = 678;
}
// 请注意:printWidth() 不是任何类的成员函数
void printWidth(Box box)
{
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
cout << "Width of box : " << box._width << endl;
}
int main()
{
Box box(1010);
printWidth(box);
return 0;
}
而构造函数初始化列表能只能初始化一次。
用构造函数初始化列表初始化对象
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
#include <iostream>
using namespace std;
class CExample
{
private:
int _a;
double _b;
char _c;
public:
//构造函数初始化列表
CExample(int a = 1, float b = 2.0, char c = 'a')
: _a(0)
, _b(8.8)
, _c('a')
{
//_c = 'z';
}
};
int main()
{
CExample C;
return 0;
}
如果成员变量在声明的时候给缺省值会出现什么效果:
我们发现使用初始化列表初始化成员变量,那么上面的缺省参数就不参与赋值
如果我们不适用初始化列表,那缺省参数会起作用吗:
结果发现:声明成员变量的时候,这里给出的缺省参数就是给初始化列表使用的。
初始化列表的特性
(1)初始化列表能只能初始化一次,多次初始化会报错:
(2)编译器也允许构造函数赋初值和初始化列表初始化混用:
我们这里使用构造函数初始化列表来初始化对象的成员变量,但是_c并没有在初始化列表里面,所以编译器会将声明时候的缺省值char _c = 'c'
初始化_c变量,之后又使用构造函数对_c进行赋初值,也就是说最后该对象中_c的值就是'z'
(3)const成员变量、引用成员变量、没有默认构造函数的自定义类型成员只能在初始化列表初始化:
引用变量必须在定义的地方初始化(不然会报错):
C++规定初始化列表是每一个成员定义的地方
#include <iostream>
using namespace std;
class CExample
{
private:
int _a;
double _b;
char _c = 'c';
//这里仅仅只是声明引用 引用必须在定义的地方初始化
int& b;
public:
//构造函数初始化列表
CExample(int a = 1, float b = 2.0, char c = 'a')
: _a(0)
, _b(8.8)
//初始化列表就是成员定义的地方,引用必须在定义的地方初始化
, b(_a)
{
_c = 'z';
}
};
int main()
{
CExample C;
return 0;
}
const类型的变量必须在定义的时候赋初值(不然会报错)
所以const类型的成员变量必须在定义的时候初始化(初始化列表就是每个成员定义的地方)
没有默认构造函数的自定义类型成员变量必须在定义的时候初始化
默认构造函数:我们不写,编译器自动生成的默认构造函数、带参全缺省的构造函数、用户自己写的无参构造函数
构造函数的特点:对于内置类型不做处理(int float double int* …),自定义类型会调用它的默认构造
class A
{
public:
A(int a) //普通构造函数,不是默认构造
{
_a = a;
}
private:
int _a;
};
class CExample
{
private:
int _a;
double _b;
char _c = 'c';
//这里仅仅只是声明引用 引用必须在定义的地方初始化
int& b;
A _aa;
public:
//构造函数初始化列表....
};
上述代码中对象_aa是自定义类型,如果我们不写初始化列表,那么就是调用它自己的默认构造,但是对象_aa并没有默认构造,所以此程序就会无法编译
更改方法:1.不使用初始化列表初始化对象_aa,给它添加上默认构造函数
2.使用初始化列表初始化成员变量
#include <iostream>
using namespace std;
class A
{
public:
A(int a) //不是默认构造函数
{
_a = a;
}
private:
int _a;
};
class CExample
{
private:
int _a;
double _b;
char _c = 'c';
//这里仅仅只是声明引用 引用必须在定义的地方初始化
int& b;
A _aa;
public:
//构造函数初始化列表
CExample(int a = 1, float b = 2.0, char c = 'a')
: _a(0)
, _b(8.8)
, b(_a)
, _aa(12345)
{
_c = 'z';
}
};
int main()
{
CExample C;
return 0;
}