数据的共享和保护
作用域
函数原型作用域:
void fun(int a); //这里是一个函数原型声明,变量a的作用域就是函数原型作用域,仅在括号之内
局部作用域:
函数定义时的形参,函数内部声明的变量,以及代码块内的变量,都是局部变量,处于局部作用域。
类作用域:声明在class中的属性或方法
命名空间作用域:声明在命名空间中的内容。
采用using关键字使用命名空间的资源:using namespace spaceName;全部空间中的资源都可直接使用。或者,using spaceName::ResourceName;仅使用该空间中指定的该资源。
命名空间可以嵌套,使用的时候需要连缀使用域操作符::
全局命名空间:全局变量,即声明在指定的namespace之外的全局的资源都属于一个无名的全局命名空间,全局可以直接使用。在函数体内有重复名称的时候,直接用::表示调用全局命名空间的资源,即全局变量。
匿名命名空间:
namespace { body }
。作用是为了其他源文件不能访问该命名空间中的内容。
// test unnamed namespace namespace { int a = 10; int b = 20; } int a = 30; void test2() { // cout << a << endl; // 错误,a不知道是匿名空间的还是全局的 cout << ::a << endl; // 30 cout << b << endl; // 20,匿名空间中的资源相当于static,可直接在本源文件中使用。 }
生存期
生存期指资源创建到结束的这段时间。
静态生存期:与程序同生死,程序运行阶段都存在的资源,如全局变量。
命名空间作用域中的资源都是静态生存期的。
若在函数中(局部)声明静态的变量,需要用static关键字,
函数中声明变量用static等同于该变量变成了全局的,且每次调用该函数,该static变量值不会重置。
函数中static和全局的static关键字作用不同。全局的static是限定该变量的作用域,限定在本代码文件中,不能被其他文件引用,c++不再提倡使用static(提倡在class中用static,全局用匿名namespace达到同样目的)。而函数中的static是改变变量的生存期的,由local变成global。
动态生存期:除了静态(全局)生存期,其他都是动态生存期(局部生存),从声明处到代码块结束。
上述描述没有涉及类的静态成员。
类的静态成员
类的静态成员,属于该类的资源,而不是单属于某一个对象,它可以为该类的所有对象而公用,实现数据共享。最典型的如类的对象个数统计。
静态成员通过static声明。可以通过类名::varName
调用。
class中的static变量,仅仅是一个声明,需要在外部重新为它定义(声请内存空间,或者同时赋初值)
class Foo{
private:
static int count; // 静态数据成员 声明,显然这里用于统计Foo类的对象个数
public:
Foo(){count++;}
~Foo(){count--;}
}
int Foo::count = 0; // 分配空间并赋初值。
同理,还有类的静态函数,或者说静态方法,静态方法不能直接访问非静态属性。
友元
友元实际上就是主动告诉别人,我是你的朋友,你可以使用我的资源。从而打破原有的访问控制规则。
通过friend
声明友元关系。
- 友元函数:可以是一般函数或其他类的成员函数。在本类中声明,但它不属于本类的函数,但是它的函数体内,可以调用本类的资源。
- 友元类:A类是B类的友元类(在B类中声明friend class A,表示A是我的朋友),则A中所有成员函数都是B的友元函数,则A中函数都可以访问B的受限资源。
- 原则:
- 友元关系不能传递。
- 友元关系单向的。
- 友元关系不能被继承。
常量
常成员函数:
返回类型 方法名(参数列表) const; // 函数原型
- 在函数定义的时候const也需要带上。
- 一个常对象只能调用它的常方法。
- const算是一个函数重载条件。
- const常成员函数不能修改对象的数据成员。
常数据成员:类的const属性
- 则类的任何函数都不能修改该常量值。
- const常数据成员只能通过构造函数的初始化列表进行初始化。
class A{ pirvate: const int a; static const int b; public: A(int i); } // 初始化常量成员,构造函数的初始化列表 A::A(int i) : a(i){ void;} // 静态常量成员初始化 const int A::b = 0;
常引用:const &,常引用的对象不能被修改,常用作函数参数类型,避免栈中创建临时对象,减少开销。
编译预处理命令
tips:将需要分配空间的定义放在源文件中,将不需要分配空间的声明放在头文件中。
预处理器在编译器编译源程序之前工作,可以通过预处理指令制定一些预处理工作。
- #include
- #define 定义宏 #undef 删除宏
- 条件编译:#if #ifdef #ifndef #else #elif #endif