文章目录
一、默认值形参与位域
默认值形参
有默认值的形参必须在形参列表最后,
调用时未给实参则按采用默认值,未给全则按左至右优先
定义及多个声明中只能定义一次默认值
位域
将类中多个数据成员打包,使不同成员共享相同字节
仅bool,char,int,enum类型的成员能被定义为位域
节省内存空间,增加运行时间
数据类型说明符 成员名:二进制位数;
unsigned number:27;
二、存储类型
auto:堆栈,暂时性存储,存储空间可呗若干变量多次覆盖使用
registger:存储在通用寄存器
extern:所有函数和程序段都可引用
stastic:以固定地址存放,整个程序运行期间都有效
三、生存期
1、静态生存期
对象的生存期与程序运行期相同,则具有全局寿命,
函数内部局部作用域中声明具有静态生存期的对象要用static,局部可见,只第一次进入函数时被初始化
2、动态生存期
局部作用域中声明的具动态生存期的对象,诞生于声明点,结束于声明所在块执行完毕时,每次进入函数都初始化
四、Setiosflags、setprecision操作符
#include <iomanip>
对齐方式
左对齐:ios_base::left
右对齐:ios_base::right
cout << setiosflags(ios_base::left) << setw(8) << name
以1位有效数字显示浮点数
cout << setw(8)<< setprecision(1) << value
五、逗号表达式
a=1+1,2+2;
先解1+1,再解2+2
结果为2+2
六、关系运算优先级
关系运算优先级
较高:< <= > >=
较低:= !=
七、逻辑运算优先级
逻辑运算优先级
! && || (高-低)
(a == b) && (++c==1)
前面表达式不成立时不会执行后面表达式
||则相反
八、三目运算符
1 ? 2 : 3
1必须是bool型
九、数组
1、二维数组
二维数组:int a[3] [4]; 总共12个元素,可当做3行4列看待,名字依次是
a[0] [0] a[0] [1] a[0] [2] a[0] [3]
a[1] [0] a[1] [1] a[1] [2] a[1] [3]
a[2] [0] a[2] [1] a[2] [2] a[2] [3]
a[ i ] [ j ]表示第 i+1 行 j+i 列的元素
初始化:
int a[3] [4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int a[3] [4] = {
{ 1, 2, 3, 4},
{ 5, 6, 7, 8},
{ 9, 10, 11, 12} };
2、对象数组
元素是对象
类名 数组名 [常量表达式];
通过这个对象,便可以访问到它的公有成员
数组名[下标表达式].成员名
a[i].move(i, i + 10);
SavingsAccount a[] = {
SavingsAccount(date, "hehe7", 0.015),
SavingsAccount(date, "yaya2", 0.015)
};
十、指针
数据类型 *标识符;
int * p; 表示声明指针:出现在声明语句
cout << *p; 输出p所指内容,表示访问指针所指对象的内容:出现在执行语句或声明语句的初始化表达式
int &rf; 声明引用
int *p = &b; 表示取对象的地址:给变量赋值时=右边或在执行语句中
可声明指向常量的指针 const int * p1 = &b;
可声明指针类型常量 int * const p2 = &a; 指针本身的值不能改变
void类型的指针可存储任何类型的对象地址 void *pv;
p[-i] 等价于 *(p-i)
指针变量可与整数0比较,为0、NULL表示空指针(不指向任何有效地址的指针)
1、指针数组
数据类型 *数组名[下标表达式]; int * p[3];
p[i][j] 等价于 *(p[i]+j)
数组内容是new来的: 一个个释放
for (int i=0;i<n;i++)
{
delete []pStrArray[i];
}
delete pStrArray;
2、指针型函数与函数指针
指针型函数:
数据类型 *函数名(参数表){。。。 };
函数指针:专用于存放函数代码首地址的变量
数据类型 (*函数指针名)(参数表);
赋值:函数指针名 =函数名;
3、对象指针
存放对象地址的变量
类名 *对象指针名;
访问对象的成员:
对象指针名 ->成员名 等价 (*对象指针名).成员名
4、this指针
隐含于每个类的非静态成员函数中的特殊指针,用于指向正在被成员函数操作的对象
执行成员函数获取成员数据时 return x;对系统来说执行的是 return this->x;
class A
{
int num;
public:
void setnum(int num)
{
///这个时候你直接写num=num就会产生二义性而混淆,但你可以用this
this->num = num;
}
};
5、智能指针
将普通的指针封装为一个栈对象,以类模板方式实现,C++11废弃了auto_ptr新增以下3个
①unique_ptr
保证同一时间内只有一个智能指针可以指向该对象,避免资源泄露
unique_ptr < string > pu1(new string ("hello world"));
unique_ptr < string > pu2;
pu2 = pu1; // #1 不允许(pu1的所有权会被剥夺)
unique_ptr < string >pu3;
pu3 = unique_ptr < string > (new string ("You"));// #2 允许(右值是临时的,调用unique_ptr的构造函数创建的临
//时对象在其所有权让给pu3后就被销毁)
②shared_ptr
当两个对象相互使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。
多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。采用引用计数,记录当前内存资源被多少个智能指针引用。通过make_shared函数或者通过构造函数传入普通指针,通过get函数获得普通指针。
成员函数:
use_count 返回引用计数的个数
unique 返回是否是独占所有权( use_count 为 1)
swap 交换两个 shared_ptr 对象(即交换所拥有的对象)
reset 放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引用计数的减少
get 返回内部对象(指针), 由于已经重载了()方法, 因此和直接使用对象是一样的.
shared_ptr<int> sp(new int(1)); 等价sp.get()
③weak_ptr
不控制对象生命周期的智能指针,指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的shared_ptr, weak_ptr只是提供了对管理对象的一个访问手段。
只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。解决shared_ptr相互引用时的死锁问题
class B; //声明
class A { public:shared_ptr<B> pb_; //改为weak_ptr <B>pb_就不会内存泄漏 };
class B { public:shared_ptr<A> pa_; };
int main() { shared_ptr <B> pb(new B());
shared_ptr<A> pa(new A());
pb-> pa_ = pa;
Pa-> pb_ = pb; }
6、指向类的非静态成员的指针 与 指向类的静态成员的指针
指向类的非静态成员的指针
类型说明符 类名::*指针名; 声明指向数据成员的指针
类型说明符 (类名::*指针名)(参数表); 声明指向函数成员的指针
对数据成员指针赋值:
指针名 =& 类名::数据成员名;
访问数据成员:
对象名.*类成员指针名 或 对象指针名->*类成员指针名
对成员函数指针赋值:
指针名 =& 类名::函数成员名;
调用成员函数:
(对象名.*类成员指针名)(参数表) 或(对象指针名->*类成员指针名)(参数表)
指向类的静态成员的指针:
对类的静态成员的访问不依赖于对象,可用普通指针指向和访问
十一、结构体
struct 结构体名称
{ 【public: 】 可省略,未指定访问控制属性成员为公有类型
公有成员
protected: 保护型成员
private: 私有成员
};
全为公有成员时赋初值
类型名 变量名={成员数据1初值,成员数据2初值,....};
十二、联合体
默认访问控制属性为公有。全部数据成员共享同一组内存单元
不能继承,不支持多态,可不声明名称,变量中成员同时只有一个有意义
union 【联合体名称】
{ 公有成员
protected: 保护型成员
private: 私有成员 };
十三、动态内存分配
程序在运行过程中按实际申请适量内存,使用结束可释放
动态创建堆对象:
new 数据类型(初始化参数列表);//把参数存入该空间
若内存申请成功,new运算返回一个指向新分配内存首地址的类型的指针,可通过此指针对堆对象访问。申请失败,会抛出异常 int *p = new int;
删除由new建立的对象,释放指针指向的内存空间:new建立的对象只能删除一次(delete后将指针置空,则再次delete不会出错)
delete 指针名; 若删除对象,该对象的析构函数将被调用
创建数组类型的对象:
new 类型名 [数组长度(可是任何能得到正整数值的表达式)];
删除:delete[] 指针名;
多维数组:new 类型名T[数组1维长度][数组2维长度]。。。;
其中第1维可为任何能得到正整数值的表达式,其他各维必须是结果为正整数的常量表达式
若内存申请成功,new运算返回一个指向新分配内存首地址的类型的指针,但不是T类型指针,是指向T类型数组的指针。
float (*cp)[25][10];
cp = new float[10])[25][10]; cp是指向二维float型数组的指针
使用注意:
- new 和delete都是内建的操作符,语言本身所固定了,无法重新定制,想要定制new和delete的行为,徒劳无功的行为。
- 动态分配失败,则返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。
- 指针删除与堆空间释放。删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身(指针p本身并没有撤销,它自己仍然存在,该指针所占内存空间并未释放),释放堆空间后,p成了空指针。
- 内存泄漏(memory leak)和重复释放。new与delete 是配对使用的, delete只能释放堆空间。如果new返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。
- 动态分配的变量或对象的生命期。我们也称堆空间为自由空间(free store),但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放,往往会出错。
- 要访问new所开辟的结构体空间,无法直接通过变量名进行,只能通过赋值的指针进行访问。
用new和delete可以动态开辟和撤销地址空间。在编程序时,若用完一个变量(一般是暂时存储的数据),下次需要再用,但却又想省去重新初始化的功夫,可以在每次开始使用时开辟一个空间,在用完后撤销它。