c++之数据的共享与保护入门

c++ — 数据的共享与保护

标示符的作用域与可见性

作用域分类:
1、函数原型作用域:
函数原型中的参数,从函数声明的左“(”开始到右“)”结束。
2、局部作用域(块作用域):
函数的形参、在块中声明的标识符。
3、类作用域:
类的成员,范围包括类体和成员函数体。
 在类作用域外访问类成员:
  静态成员:通过类名,或者该类的对象名、对象引用访问
  非静态成员:通过类名,或者该类的对象名、对象引用、对象指针访问。
4、文件作用域:
不在前述各个作用域中出现的声明,就具有文件作用域。始于声明点,结束于文件尾。
5、命名空间作用域(详见后续章节)

可见性
1、可见性是从对标识符的引用的角度来谈的概念;
2、可见性表示从内层作用域向外层作用域“看”时能看见什么;
3、如果标识符在某处可见,就可以在该处引用该标识符。
简单来说:
1、如果某一个标识符在外层声明,在内层没有相同的标识符的声明,则该标识符在内层可见;
2、对于两个嵌套的作用域,如果内层作用域声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见(被覆盖)。
例:

#include <iostream>
using namespace std;

int i;
int main()
{
	i=10;
	{
		int i=5;
		cout<<"i="<<i<<endl;
	}
	cout<<"i="<<i<<endl;
	return 0;
}

结果为:
i=5
i=10

对象的生存期

静态生存期:
1、这种生存期与程序的运行期相同;
2、在文件作用域中声明的对象拥有这种生存期;
3、在函数内部声明静态生存期对象要用static关键字(但作用域不改变)。
动态生存期:
1、开始于声明点,结束于该标识符作用域结束处;
2、块作用域中声明的没有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;     //a为静态局部变量,具有全局寿命,局部可见 
	int b=-10;       
	int c=0;          //b,c为局部变量,具有动态生存期 
	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;
}

结果:
在这里插入图片描述

类的静态数据成员

1、用关键字static声明;
2、为该类的所有对象共享,静态数据成员具有静态生存期;
3、必须在类外定义和初始化,用“::”来指明所属的类。

#include <iostream>
using namespace std;

class Point{
public:
	Point(int x=0,int y=0):x(x),y(y){count++;}
	Point(Point &p){
		x=p.x;y=p.y;count++;
	}
	~Point(){count--;}
	int getX(){return x;}
	int getY(){return y;}
	void showCount(){
		cout<<"count="<<count<<endl;
	}
private:
	int x,y;
	static int count;        //对于同一类的所有对象都是通用的
};

int Point::count=0;

int main()
{
	Point a(3,4);
	cout<<"A:"<<a.getX()<<","<<a.getY()<<endl;
	a.showCount();
	Point b(5,6);
	cout<<"B:"<<b.getX()<<","<<b.getY()<<endl;
	b.showCount();
	return 0;
}

在这里插入图片描述

类的友元

1、友元时c++中提供的一种破坏数据封装和数据隐藏的机制;
2、通过将一个模块声明为另一个模块的友元,一个模块就能引用另一个模块中本是被隐藏的信息;
3、可以声明友元函数和友元类;
4、为确保数据的完整性及数据封装与隐藏的原则,建议慎用友元。
友元函数:
1、友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问private和protected成员;
2、作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择;
3、范文对象中的成员必须通过对象名。

#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 double dist(Point &a,Point &b);     //dist函数为Point类的友元 
private:
	int x,y;
};

double dist(Point &a,Point &b)
{
	double x=a.x-b.x;
	double y=a.y-b.y;
	return sqrt(x*x+y*y);
}

int main()
{
	Point p1(1,1),p2(4,5);
	cout<<"the distance is"<<dist(p1,p2);
	return 0;
}

在这里插入图片描述
友元类:
1、若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员;
2、语法:将友元类名在另一个类中使用friend修饰说明。
例:
class A{
friend class B;      //B为A的友元,B可以访问A的私有成员
public:
 void display(){cout<<x<<endl;}
private:
 int x;
};

class B{
public:
 void set(int i);
 void display();
private:
 A a;
};

void B::set(int i)
{
 a.x=i;       //B直接访问A的私有成员x
}

void B::display()
{
 a.display;
}
注:
友元关系是单向的,每个类只有授权别的类为友元来访问自己的私有成员,而不能要求自己为别的类的友元去访问别的类的私有成员。

共享数据的保护

常类型:
1、常对象: 必须进行初始化,不能被更新。
const 类名 对象名;
2、常成员:用const进行修饰的类成员。(常数据成员和常函数成员)
3、常引用:被引用的对象不能被更新。(只读的引用)
const 类型说明符 &引用名;
4、常数组:数组元素不能被更新。
类型说明符 const 数组名[大小]… …
5、常指针:指向常量的指针。
常成员函数:
1、使用const关键字说明的函数;
2、常成员函数不更新对象的数据成员;
3、格式:
类型说明符 函数名(参数表) const;
(const是函数类型的一个组成部分,因此在实现部分也要带const关键字)
4、const关键字可以被用于参与对重载函数的区分;
5、通过常对象只能调用它的常成员函数。
常数据成员:
使用const修饰的数据成员。

#include <iostream>
using namespace std;

class A{
public:
	A(int i):a(i){}       //a仅能在初始化列表中赋值,而不能在构造函数体中赋值 
	void print();
private:
	const int a;              //常数据成员,用前必须赋初始值
	static const int b;      //静态常数据成员,为所有对象所共享 
};

const int A::b=10;           //将b赋初始值 

void A::print()
{
	cout<<a<<":"<<b<<endl;
}

int main()
{
	A a(100),b(0);
	a.print();
	b.print();
	return 0;
}

结果
在这里插入图片描述
常引用:
在友元中用常引用做参数,既能获得较高的执行效率,也能保证实参的安全性。

#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 double dist(const Point &a,const Point &b);   //常引用   
private:
	int x,y;
};

double dist(const Point &a,const Point &b)
{
	double x=a.x-b.x;
	double y=a.y-b.y;   //只能读取a.x,a.y,b.x,b.y的值,不能修改
	return sqrt(x*x+y*y);
}

int main()
{
	Point p1(1,1),p2(4,5);
	cout<<"the distance is"<<dist(p1,p2);
	return 0;
}

多文件结构和预编译命令

c++程序一般组织结构:
1、一个工程可划分为多个源文件,例如:
类声明文件(. h文件)
类实现文件(. cpp文件)
类的使用文件(main()所在的 . cpp文件)
2、利用工程来组合各个文件
外部变量:
1、除了定义它的源文件中可以使用外,还能被其他文件使用;
2、文件作用域中定义的变量,默认都是外部变量;
3、在其他文件中如果需要使用,需要用extern关键字声明。
外部函数:
1、在所有类之外声明的函数(非成员函数),都是具有文件作用域的;
2、这样的函数可以在不同编译单元中被调用;
3、只要在被调用前进行引用性声明(声明函数原型)即可。
将变量和函数限制在编译单元内:
1、在匿名命名空间中定义的变量和函数,都不会暴露给其他的编译单元;
namespace{      //匿名命名空间
 int n;
 void f(){}
}

标准c++库:
标准c++库是一个极为灵活并可扩展的可重用软件模块的集合,在逻辑上分为6种类型:
输入输出类
容器类与抽象数据类型
存储管理类
算法
错误处理
运行环境支持

编译预处理命令:
1、#include包含指令
将一个源文件嵌入到当前文件该点处
#include <文件名>
按标准方式搜索。(搜索c++系统默认的安装目录下)
#include “文件名”
先在当前目录搜索,若找不到,则再按标准方式搜索。
2、#define宏定义指令
定义符号常量(很多情况下已被const取代)
定义带参数宏(已被内联函数取代)
3、#undef
删除由#define定义的宏,使其不再起作用。
4、#if、#endif、#else、#elif—条件编译指令
#if 常量表达式     //当常量表达式为真时编译
 程序正文
#endif

#if 常量表达式     //当常量表达式为“真”时编译
 程序正文1
#else         //当常量表达式为“假”时编译
 程序正文2
#endif

#if 常量表达式1     //当常量表达式1“非零”时编译
 程序正文1
#elif 常量表达式1       //当常量表达式2“非零”时编译
 程序正文2
#else          //其他情况下编译
 程序正文3      
#endif

5、#ifdef、#ifndef
#ifdef 标识符
程序段1
#else
程序段2
#endif
如果标识符经define定义过后,未经undef删除,则编译程序段1,否则编译程序段2。

#ifndef 标识符
程序段1
#else
程序段2
#endif
如果标识符未被定义过则编译程序段1,否则编译程序段2。

发布了30 篇原创文章 · 获赞 33 · 访问量 1276

猜你喜欢

转载自blog.csdn.net/weixin_45949075/article/details/104022664