一、标识符的作用域与可见性
二、对象的生存期
1. 静态生存期
- 这种生存期与程序的运行期相同。
- 在文件作用域中声明的对象具有这种生存期。
- 在函数内部声明静态生存期对象,要冠以关键字
static
。
2. 动态生存期
- 块作用域中声明的,没有用static修饰的对象是动态生存期的对象(习惯称局部生存期对象)。
- 开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。
三、变量的生存期与可见性综合示例
思考:在函数内部定义的普通局部变量和静态局部变量在功能上有何不同?计算机底层对这两类变量做了
怎样的不同处理?
- 局部作用域中的静态变量: 不会随着每次函数的调用而产生一个副本,也不会随着函数的返回而失效,定义时未指定初值的会被以0初始化
- 局部作用域中的全局变量:诞生于声明点,结束于声明所在块执行完毕之时,并且不指定初值意味着初值不确定
四、类的静态成员 static
静态成员函数/变量本质上是全局函数/变量,哪怕一个对象都不存在,类的静态成员都还是存在的。
那为什么还要设置静态成员而不直接设置成全局函数/变量呢?
- 是为了将和某些类紧密相关的全局变量和函数写到类里面,使其看上去像一个整体,便于维护和理解。
注:私有的静态成员在类外依然不能访问
1. 静态成员变量
1 | class A{ |
- 所有对象共享,维护同一个副本,即对象 n1 修改其值,对象 n2 中的值也会改变。
- sizeof(A) = 4;sizeof不会计算静态成员变量
- 静态成员变量必须在类外进行一次说明或初始化,否则编译能通过但链接不能通过
2. 静态成员函数
普通成员函数必须具体作用于某个对象(即通过 对象名. 访问),
而静态成员函数并不具体作用于某个对象,不需要通过对象就能访问。
静态成员函数的访问方式:
- 类名::成员名(无须对象,直接通过类名访问)
1 | Point::showCount(); |
- 对象名.成员名
1 | A a; |
但并不意味着只作用于a上面
- 指针->成员名
1 | A *p; |
但并不意味着只作用于a上面
- 引用.成员名
1 | A &q = a; |
但并不意味着只作用于a上面
注:静态成员函数要访问非静态成员变量必须通过对象名.
1 | class A |
五、类的友元 friend
1. 友元函数
2. 友元类
特别注意:友元关系不能继承;不能传递;单向 !
六、共享数据的保护 (const)
Java 中没有
const
关键字,与之替代的是final
1. 常对象
用 const 修饰的对象
- 常量对象的值不可被修改
- 常量对象不能执行非常量成员函数,因为非常量成员函数有可能对成员变量进行修改;
- 常量对象可以执行常量成员函数
例:
1 | class A{ |
2. 常成员
用 const 修饰的对象成员
常成员函数
例:
常成员函数执行期间不应该修改其所作用的对象,即
- 在常量成员函数中不能修改成员变量的值(静态成员变量除外)
- 也不能调用同类的非常量成员函数(静态成员函数除外)
例:
1 | class A{ |
常数据成员
使用 const 说明的数据成员
- 常数据成员 const 只能通过构造函数的初始化列表来获得初值
- 静态常数据成员 static const 在类外进行说明和初始化
例:
3. 常引用
当需要对象作为参数时,生成该参数需要调用复制构造函数,效率比较低,用指针做参数,代码会比较不好看,所以用对象的引用做参数void func(A &a)
使用对象引用作参数有一定的风险性,若函数中修改了形参a,则实参也跟着变,有时候这可能不是开发者想要的。若不想要对象发生改变,则使用const限定:void func(const A &a)
例: