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