一、标识符的作用域与可见性
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常指针
指向常量的指针