一、标识符的作用域与可见性
1.1作用域
作用域是一个标识符在程序正文中有效的区域
分类
1、函数原形作用域
函数原型中的参数,其作用域始于 " ( ",止于" ) ",限与小括号内
2、局部作用域(块作用域)
函数的形参、在块中声明的标识符的作用域;自声明处起,限于块中
void fun(int a) { //a的范围在整个函数 int b = a; //b的范围仅限fun函数体 cin >> b; if (b > 0) { int c; //c的范围仅限if语句 ...... } }
3、类作用域
类的成员具有类作用域,其范围包括类体和非内联成员函数的函数体
如果在类作用域以外访问类的成员,要通过类名(访问静态成员),或者该类的对象名、对象引用、对象指针(访问非静态成员)
4、文件作用域
不在前述各个作用域中出现的声明的标识符,就具有文件作用域,始于声明处,止于文件尾
5、命名空间作用域
1.2可见性
可见性是从对标识符的引用的角度来谈的概念,表示从内层作用域向外层作用域“看”时能看见什么
1、如果标识在某处可见,就可以在该处引用此标识符
2、如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见
3、对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见(被屏蔽)
二、对象的生存期
2.1静态生存期
与程序的运行期相同
在文件作用域中声明的对象具有这种生存期
在函数内部声明静态生存期对象,要冠以关键字 static
2.2动态生存期
始于声明处,止于命名该标识符的作用域结束处
块作用域中声明的,没有用 static 修饰的对象是动态生存期的对象(习惯称局部生存期对象)
三、类的友元
友元是 C++ 提供的一种破坏数据封装和数据隐藏的机制
类的友元关系是单向的。如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有和保护数据
为确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元
3.1友元函数
友元函数是在类声明中由关键字 friend 修饰说明的非成员函数,在其函数体中能够通过对象名访问 private 和 protected 成员
作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择
访问对象中的成员必须通过对象名
//1.2例 #include<iostream> using namespace std; int i; //全局变量,文件作用域 int main() { i = 5; //为全局变量i赋值 { int i; //局部变量,局部作用域 i = 7; cout << "i = " << i << endl; //输出7 } cout << "i = " << i << endl; //输出5 return 0; } 结果: i = 7 i = 5 //2.2例 #include<iostream> using namespace std; int i = 1; // i 为全局变量,具有静态生存期 void other() { static int a = 2; static int b; //a,b为静态局部变量,具有全局寿命,局部可见, 只在第一次进入函数时被初始化 int c = 10; //c为局部变量,具有动态生存期,每次进入函数时都初始化 a += 2; i += 32; c += 5; cout << "---OTHER---\n"; cout << " i: " << i << " a: " << a << " b: " << b << " c: " << c << endl; b = a; } int main() { static int a; //静态局部变量,有全局寿命,局部可见 int b = -10; //b, c为局部变量,具有动态生存期 int c = 0; cout << "---MAIN---\n"; cout << " i: " << i << " a: " << a << " b: " << b << " c: " << c << endl; c += 8; other(); cout << "---MAIN---\n"; cout << " i: " << i << " a: " << a << " b: " << b << " c: " << c << endl; i += 10; other(); return 0; } 结果: ---MAIN--- i: 1 a: 0 b: -10 c: 0 ---OTHER--- i: 33 a: 4 b: 0 c: 15 ---MAIN--- i: 33 a: 0 b: -10 c: 8 ---OTHER--- i: 75 a: 6 b: 4 c: 15 //3.1例 //此例亦为常引用举例 #include <iostream> #include <cmath> using namespace std; class Point { public: Point(int x = 0, int y = 0) : x(x), y(y) { } int getX() { return x; } int getY() { return y; } friend float dist(Point &a, Point &b); private: int x, y; }; float dist(const Point& a, const Point& b) { //将引用设置为常引用不会意外地发生对实参的更改 double x = a.x - b.x; double y = a.y - b.y; return (float)sqrt(x * x + y * y); } int main() { Point p1(1, 1), p2(4, 5); cout << "The distance is: "; cout << dist(p1, p2) << endl; return 0; } 结果: The distance is: 5
3.2友元类
若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员
```c++
class A {
friend class B; //类B是类A的友元(关键)
public:
void display() {
cout << x << endl;
}
private:
int x;
};
class B {
public:
void set(int i);
void display();
private:
A a; //类B可以访问类A的任意成员
};
//接口与实现分离
void B::set(int i) {
a.x = i;
}
void B::display() {
a.display();
};
```
四、共享数据的保护
对于既需要共享、又需要防止改变的数据应该声明为常类型(用 const 进行修饰)
4.1常对象
必须进行初始化, 且不能被更新
语法形式const 类名 对象名
class A { public: A(int i, int j) { x = i; y = j; } private: int x, y; }; const A a(3, 4); //a是常对象,不能被更新
4.2常成员
4.2.1常数据成员
语法形式const 数据类型 变量名
不为常数据成员提供成员初始化值是编译错误;成员初始化值是成员初始化列表的一部分,由数据成员名和其后包含该成员初始值的括号组成
常数据成员和引用数据成员必须通过成员初始化列表初始化;成员初始化列表在构造函数的形参列表和大括号之间;成员初始化列表在函数体之前执行
4.2.2常成员函数
语法形式返回值类型 函数名(参数表)const { 函数体 }
关键字const在函数原型和函数定义中都要说明,即在函数原型和函数定义的形参列表后加关键字 const
常对象只能调用常成员函数,且不改变对象的数据成员
将构造函数和析构函数声明为 const 是编译错误
#include<iostream> using namespace std; class A { public: A(int i) : a(i) { } void printA(); private: const int a; static const int b; //静态常数据成员 }; class R { public: R(int r1, int r2) : x(r1), y(r2) { } void print(); void print() const; //const也是区分重载函数的一个因素 private: int x, y; }; const int A::b = 10; void A::printA() { cout << a << ":" << b << endl; } void R::print() { cout << x << ":" << y << endl; } void R::print() const { //显式的标出const,编译器才会认真审查函数是否改变对象状态 cout << x << ":" << y << endl; } int main() { //常数据成员 A c(16); c.printA(); cout << endl; //常成员函数 R a(5, 4); a.print(); //调用void print();若没有定义该函数,对象a调用常函数。普通对象可以调用常函数 const R b(20, 52); //定义的常对象只能用常函数处理;不是常函数,不能通过常对象调用 b.print(); //调用void print() const return 0; } 结果: 16:10 5:4 20:52
4.3常引用
被引用的对象不能被更新
语法形式const 类型说明符 &引用名
举例:见友元函数举例
4.4常数组
数组元素不能被更新
语法形式类型说明符 const 数组名[大小]
4.5常指针
指向常量的指针