C++(3)数据共享与保护

目录

一、标识符的作用域与可见性

作用域

可见性

二、对象的生存期

静态生存期

动态生存期

三、类的友元

友元函数

友元类

四、共享数据的保护


一、标识符的作用域与可见性

作用域

作用域是一个标识符在程序正文中有效的区域

分类

·函数原型作用域

·局部作用域(块作用域)

·类作用域

·文件作用域

·命名空间作用域

1)函数原形作用域

·函数原型中的参数,其作用域始于"(",止于")"

double area(double radius);

2)局部作用域

·函数的形参、在块中声明的标识符的作用域,自声明处起,限于块中

void fun(int a) {    //a的范围在整个函数
	int b = a;    //b的范围仅限fun函数体
	cin >> b;
	if (b > 0) {
		int c;    //c的范围仅限if语句
		......
	}
}

3)类作用域

·类的成员具有类作用域,其范围包括类体和非内联成员函数的函数体

·如果在类作用域以外访问类的成员,要通过类名(访问静态成员),或者该类的对象名、对象引用、对象指针(访问非静态成员)

4)文件作用域

·不在前述各个作用域中出现的声明,就具有文件作用域,这样声明的标识符其作用域开始于声明点,结束于文件尾

5)命名空间作用域

可见性

可见性是从对标识符的引用的角度来谈的概念,表示从内层作用域向外层作用域“看”时能看见什么

·如果标识在某处可见,就可以在该处引用此标识符

·如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见

·对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见(被屏蔽)

举例:

#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;
}

二、对象的生存期

静态生存期

·与程序的运行期相同

·在文件作用域中声明的对象具有这种生存期

·在函数内部声明静态生存期对象,要冠以关键字static

动态生存期

·始于程序执行到声明处,止于命名该标识符的作用域结束处

·块作用域中声明的,没有用static修饰的对象是动态生存期的对象(习惯称局部生存期对象)

举例:

#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;
}

三、类的友元

友元是C++提供的一种破坏数据封装和数据隐藏的机制

·类的友元关系是单向的。如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有和保护数据

·为确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元

友元函数

·友元函数是在类声明中由关键字friend修饰说明的非成员函数,在其函数体中能够通过对象名访问 private 和 protected 成员

·作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择

注:访问对象中的成员必须通过对象名

举例:

//此例亦为常引用举例

#include <iostream>
#include <cmath>
using namespace std;

class Point {	//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 static_cast<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;
}

友元类

·若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员

·语法形式
将友元类名在另一个类中使用friend修饰说明

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进行修饰)

1)常对象

必须进行初始化, 不能被更新

//const 类名 对象名

class A {
public:
	A(int i, int j) { x = i; y = j; }
	...
private:
	int x, y;
};
A const a(3, 4);	//a是常对象,不能被更新

2)常成员

常数据成员:    const  数据成员

举例:

#include <iostream>
using namespace std;

class A {
public:
	A(int i);
	void print();
private:
	const int a;
	static const int b;  //静态常数据成员
};

const int A::b = 10;
A::A(int i) : a(i) { }
void A::print() {
	cout << a << ":" << b << endl;
}

int main() {
	A a1(100), a2(0);	//建立对象a1和a2,并以100和0作为初值,分别调用构造函数,通过构造函数的初始化列表给对象的常数据成员赋初值
	a1.print();
	a2.print();
	return 0;
}

常成员函数:    返回值类型 函数名(参数表)const{ 函数体 }    //const是函数类型的一个组成部分

·常成员函数不更新对象的数据成员

·通过常对象只能调用它的常成员函数

举例:

#include<iostream>
using namespace std;

class R {
public:
	R(int r1, int r2) : r1(r1), r2(r2) { }
	void print();
	void print() const;    //const也是区分重载函数的一个因素 
private:
	int r1, r2;
};

void R::print() {
	cout << r1 << ":" << r2 << endl;
}
void R::print() const {    //显式的标出const,编译器才会认真审查函数是否改变对象状态 
	cout << r1 << ";" << r2 << endl;
}

int main() {
	R a(5, 4);
	a.print();    //调用void print()
	              //若没有定义该函数,对象a也调用常函数。普通对象可以调用常函数 
	const R b(20, 52);    //定义的常对象只能用常函数处理;不是常函数,不能通过常对象调用 
	b.print();    //调用void print() const
	return 0;
}

3)常引用

·被引用的对象不能被更新

·语法形式    const  类型说明符  &引用名

举例见友元函数举例

4)常数组

·数组元素不能被更新

·语法形式    类型说明符 const 数组名[大小]

5)常指针

·指向常量的指针

猜你喜欢

转载自blog.csdn.net/zjuwxx/article/details/81415690