C++实例——第五章

标识符的作用域及可见性

作用域分类

  • 函数原型作用域(函数的形参表范围起始于左括号结束于右括号)
    double area(double radius) radius的作用域仅在于此,不能用于程序正文的其他地方
  • 局部作用域(块作用域)
    函数的形参、在块中声明的标识符;
    在这里插入图片描述
  • 类作用域
    类的成员具有类作用域,其范围包括类体和成员函数体。
    在类作用域以外访问类的成员
    – 静态成员:通过类名,或者该类的对象名,对象引用访问
    –非静态成员:…对象指针访问
  • 文件作用域
    作用域开始于声明点,结束于文件尾
  • 命名空间作用域(第十章)

可见性

如果标识在某处可见,就可以在该处引用此标识符
如果内层和外层作用域中的标识符同名,则外层作用域的该标识符在内层不可见

例5-1 作用域实例。

//5_1.cpp
#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修饰的对象是动态生存期的对象

例5-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;
}
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<<"i: "<<i<<"a: "<<a<<"b: "<<b<<"c: "<<c<<endl;
	c += 10;other();
	return 0;
}

i是积累的
在这里插入图片描述

类的静态数据成员

用关键字static声明
为该类的所有对象共享
必须在类外定义和初始化,用(::)来指明所属的类

在这里插入图片描述

#include <isotream>
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;}
	static.void showCount(){  //第六章
		cout<<" Object cout = "<<count<<endl;
private:
	int x,y;
	static int count; //静态数据成员声明,用于记录点的个数
};
int Point::count = 0;//静态数据成员定义和初始化
int main(){  //主函数
	Point::showCount();//输出对象个数
	Point a(4,5);//定义对象a,其构造函数会使count增1
	cout<<"Point A:"<<a.getX()<<","<<a.getY();
	a.showCount();//输出对象个数

	Point b(a); //定义对象b,其构造函数会使count增1
	cout<<"Point B:"<<b.getX()<<", "<<b.getY();
	b.showCount(); 
	return 0;
}

静态函数成员

  • 以前定义的函数成员都是属于对象的
  • 静态函数成员处理静态数据
  • 静态函数成员如果访问非静态成员,要通过对象来访问。

在这里插入图片描述

类的友元

破坏数据封装和数据隐藏的机制
通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息
可以声明友元函数和友元类
慎用!

友元函数

在类声明中由关键字friend修饰说明的非成员函数
在它的函数体中能够通过对象名访问private和protected成员
访问对象中的成员必须通过对象名

例5-6 使用友元函数计算两点间的距离

#include <iostream>
#include <cmath>
class Point{
public:
	Point(int x=0, int y=0):x(x),y(y){}
	int getX(){ return x; }
	int gerY(){ return y; }
	friend float dist(Point &a, Point &b);
private:
	int x,y;
};
float dist(Point &a,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;
}

友元类

//部件类
class A{
	friend class B;
public:
	void display(){
		cout<<x<<endl;
	}
private:
	int x;
};
//组合类
class B{
public:
	void set(int i);//定义一个set函数想用来设置i的值
	void display();
private:
	A a;
};
void B::set(int i){
	a.x=i;
}
void B::display(){
	a.display();
}

注意:类的友元关系是单向的!

共享数据的保护

常类型

常对象:必须进行初始化,不能被更新
const 类名 对象名;
常成员:用const进行修饰的类成员:常数据成员和常函数成员
常引用:被引用的对象不能被更新
const 类型说明 &引用名
常数组、常指针(第六章)

例5-7 常成员函数举例

#include <iostream>
using namespace std;
class R{
public:
	R(int r1, int r2):r1(ri),r2(r2){}
	void print();
	void print() const;//const也可以区分重载函数
private:
	int r1,r2;
};
void R::print(){
	cout<<r1<<":",<r2<<endl;
}
void R::print()const{
	cout<<r1<<";"<<r2<<endl;
}
int main(){
	R a(5,4);
	a.print();//调用 void print()
	const R b(20,52);
	b.print();//调用void print() const
	return 0;
}

如果定义的函数本义就是不想改变函数的状态比如print就加一个const表示一种保证

例5-8 常数据成员举例

#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;//静态成员b在类体中声明,在类体外定义初始化,因为是常量,初始化后再也也不许改变
A::A(int i):a(i){}//对象的成员A,在构造每一个对象时完成初始化,常成员不可以放在构造函数的函数体中赋值,必须在初始化列表中进行初始化,然后以后就不许赋值了
void A::print(){
	cout<<a<<":"<<b<<endl;
}
int main(){
//建立对象a和b,并以100和0作为初值,分别调用构造函数,
//通过构造函数的初始化列表给对象的昌数据成员赋初值
	A a1(100),a2(0);
	a1.print();
	a2.print();
	return 0;
}

常引用

在友元函数中用常引用做参数,既能获得较高的执行效率,又能保证实参的安全性。

例5-9 常引用作形参

#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(const Point &p1,const Point &p2);
private:
	int x,y;
};
float dist(const Point &p1,const Point &p2){
	double x = p1.x-p2.x;
	double y = p1.y-p2.y;
	return static_cast<float>(sqrt(x*x+y*y));
}

int main(){//主函数
	const Point myp1(1,1),myp2(4,5);
	cout<<"The distace is:";
	cout<<dist(myp1,myp2)<<endl;
	return 0;
}

多文件结构和预编译命令

在这里插入图片描述
例5-10 多文件工程

//文件1,类的定义,Point.h
class Point{
public:
	Point(int x = 0,int y = 0):x(x),y(y){}
	Point(const Point &p);
	~Point(){count--;}
	int getX() const{return x;}
	int getY() const{return y;}
	static void showCount();//静态函数成员
private:
	int x,y;
	static int count;//静态数据成员
};
//文件2,类的实现,Point.cpp
#include "Point.h"
#include <iostream>
using namespace std;

int Point::count = 0;//使用类名初始化静态数据成员
Point:Point(const Point &p):x(p.x),y(p.y){
	count++;
}

void Point::showCount(){
	cout<<"Object count = "<<count<<endl;
}
//文件3,主函数,5_10.cpp
#include "Point.h"
#include <iostream>
using namespace std;

int main(){
	Point a(4,5);
	cout<<"Point A:"<<a.getX()<<","<<a.getY();
	Point::showCount();
	Point b(a);//定义对象b,其构造函数回使count增1
	cout<<"Point B"<<b.getX()<<","<<b.getY();
	Point::showCount();
	return 0;
}

在这里插入图片描述
外部变量

除了在定义它的源文件中可以使用外,还能被其它文件使用。
文件作用域中定义的变量,默认情况下都是外部变量
在其它文件中如果需要使用,需要用extern关键字声明

想使用在别的文件中定义的函数
外部函数

在所有类之外声明的函数(也就是非成员函数),都是具有文件作用域的
这样的函数都可以在不同的编译单元中被调用
只要调用之前进行引用声明(即声明函数原型)即可

将变量和函数限制在编译单元中

在匿名命名空间中定义的变量和函数,都不会暴露给其它的编译单元。

namespace{
	int n;
	void f(){
		n++;
	}
}

标准C++库

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

编译预处理
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述

//client.h
//为了避免重复包含头文件,通常要使用编译与处理指令
#ifndef CLIENT_H_
#define CLIENT_H_

class Client{
	static char ServerName;
	static int ClientNum;
public:
	static void ChangeServerName(char name);
	static int getClientNum();
};

#endif //CLIENT_H_
//client.cpp
#inclue "client.h"

void Client::ChangeServerName(char name){
	Client::ServerName = name;//引用静态数据成员,注意加上“类名::”来修饰
	Client::ClientNum ++;
}
int Client::getClientNum(){
	return Client::ClientNum;
}
//test.cpp
#include <iostream>
#include "client.h"
using namespace std;
//静态数据成员不属于任何类的对象
//需要在类外进行单独的初始化
int Client::ClientNum = 0;
char Client::ServerName = 'a';

int main()
{
	Client c1;
	c1.ChangeServerName('a');
	cout<<c1.getClientNum()<<endl;
	Client c2;
	c2.ChangeServerName()<<endl;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值