第5章 C++程序的结构

目录

第1关:运行下面的程序,观察变量x、y的值

任务描述

相关知识

作用域

类作用域

命名空间作用域

限定作用域的枚举类

可见性

生存期

对象的生存期

静态生存期

动态生存期

任务要求

测试说明

代码

第2关:实现客户机(CLIENT)类

任务描述

相关知识

静态成员

静态数据成员

类的静态函数成员

类的友元

友元函数

友元类

类的友元关系是单向的

任务要求

测试说明

预期输入:无 预期输出:程序实际的输出为准代码


第1关:运行下面的程序,观察变量x、y的值

任务描述

观察程序运行中变量的作用域、生存期和可见性;

相关知识

为了你能够更好的完成本关任务,你需要掌握

  1. 作用域;
  2. 可见性;
  3. 生存期。
作用域
  • 作用域是一个标识符在程序正文中有效的区域;
  • 作用域分类 函数原型作用域; 局部作用域(块作用域); 类作用域; 命名空间作用域; 限定double area(double radius);

    radius 的作用域仅在于此,不能用于程序正文其他地方。 ##### 局部作用域

  • 函数的形参、在块中声明的标识符;
  • 其作用域自声明处起,限于块中。 
类作用域
  • 类的成员具有类作用域,其范围包括类体和非内联成员函数的函数体;
  • 如果在类作用域以外访问类的成员,要通过类名(访问静态成员),或者该类的对象名、对象引用、对象指针(访问非静态成员)。
命名空间作用域
  • 命名空间可以解决类名、函数名等的命名冲突
  • 命名空间的声明 namespace 命名空间名 { 各种声明(函数声明、类声明、……) } 例 namespace SomeNs { class SomeClass { ... }; } 引用类名:SomeNs::SomeClass obj1;
  • using语句有两种形式;
  • using 命名空间名::标识符名;
  • using namespace 命名空间; 特殊的命名空间 全局命名空间:默认的命名空间; 匿名命名空间:对每个源文件是唯一的。
限定作用域的枚举类

enum color {red, yellow, green}; //不限定作用域 enum color2 {red, yellow, green}; //错误,重复定义 enum class color2 {red, yellow, green}; //正确,限定作用域 color c = red; //全局作用域color枚举类 color2 c2 = red; // 错误,color2元素不在有效作用域内 color2 c2 = color2::red; //正确,使用了color2作用域枚举元素

可见性
  • 可见性是从对标识符的引用的角度来谈的概念;
  • 可见性表示从内层作用域向外层作用域“看”时能看见什么;
  • 如果标识在某处可见,就可以在该处引用此标识符;
  • 如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见;
  • 对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见。 


  1. #include <iostream>
  2. using namespace std;
  3. int i; //全局变量,文件作用域
  4. int main() {
  5. i = 5; //为全局变量i赋值
  6. {
  7. int i; //局部变量,局部作用域
  8. i = 7;
  9. cout << "i = " << i << endl;//输出7
  10. }
  11. cout << “i = ” << i << endl;//输出5
  12. return 0;
  13. }

运行结果: i = 7 i = 5

生存期
对象的生存期

对象从产生到结束的这段时间就是它的生存期。在对象生存期内,对象将保持它的值,直到被更新为止。

静态生存期

• 这种生存期与程序的运行期相同; • 在文件作用域中声明的对象具有这种生存期; • 在函数内部声明静态生存期对象,要冠以关键字static 。

动态生存期
  • 块作用域中声明的,没有用static修饰的对象是动态生存期的对象(习惯称局部生存期对象);
  • 开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。 例: 变量的生存期与可见性
     
      
    1. #include<iostream>
    2. using namespace std;
    3. int i = 1; // i 为全局变量,具有静态生存期。
    4. void other() {
    5. static int a = 2;
    6. static int b;
    7. // a,b为静态局部变量,具有全局寿命,局部可见。
    8. //只第一次进入函数时被初始化。
    9. int c = 10; // C为局部变量,具有动态生存期,
    10. //每次进入函数时都初始化。
    11. a += 2; i += 32; c += 5;
    12. cout<<"---OTHER---\n";
    13. cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl;
    14. b = a;
    15. }
    16. int main() {
    17. static int a;//静态局部变量,有全局寿命,局部可见。
    18. int b = -10; // b, c为局部变量,具有动态生存期。
    19. int c = 0;
    20. cout << "---MAIN---\n";
    21. cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl;
    22. c += 8; other();
    23. cout<<"---MAIN---\n";
    24. cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl;
    25. i += 10; other();
    26. return 0;
    27. }
    运行结果: ---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

任务要求

根据右侧任务挑战区中的代码去编写你需要的代码,并将代码补充在右侧任务挑战区 Begin-End 之间。

测试说明

平台会对你编写的代码进行测试,请依次在平台上输入程序的输出:

预期输入:无 预期输出: Begin... x = 1 y = 2 Evaluate x and y in main()... x = 10 y = 20 Step into fn1()... x = 1 y = 200 Back in main x = 10 y = 20

代码
#include <iostream>
using namespace std;

void fn1(int *x, int *y); 


int main()
{
	/********** Begin **********/
    int x, y ; 
	printf("Begin...\n");
    x = 1;
    y = 2;
    printf("x = %d\n", x);
    printf("y = %d\n", y);
    printf("Evaluate x and y in main()...\n");
    x = 10;
    y = 20;
    printf("x = %d\n", x);
    printf("y = %d\n", y);
    printf("Step into fn1()...\n");
    fn1(&x, &y);
    printf("Back in main\n");
    x = 10;
    y = 20;
    printf("x = %d\n", x);
    printf("y = %d\n", y);
  
	/********** End **********/
	return 0;
}

void fn1(int *x, int *y)
{
    *x = 1;
    *y = 200;
	printf("x = %d\n", *x);
    printf("y = %d\n", *y);
	
}

第2关:实现客户机(CLIENT)类

任务描述

实现客户机(CLIENT)类。声明字符型静态数据成员ServerName,保存其服务器名称;整型静态数据成员ClientNum,记录已定义的客户数量;定义静态函数ChangeServerName()改变服务器名称。

相关知识

为了你能够更好的完成本关任务,你需要掌握

  1. 静态成员;
  2. 类的友元。
静态成员
静态数据成员
  • 用关键字static声明;
  • 为该类的所有对象共享,静态数据成员具有静态生存期;
  • 一般在类外初始化,用(::)来指明所属的类;
  • C++11支持静态常量(const或constexpr修饰)类内初始化,此时类外仍可定义该静态成员,但不可再次初始化操作。

例: 具有静态数据成员的Point类

例 静态成员举例

 
  1. #include <iostream>
  2. using namespace std;
  3. class Point { //Point类定义
  4. public: //外部接口
  5. Point(int x = 0, int y = 0) : x(x), y(y) { //构造函数
  6. //在构造函数中对count累加,所有对象共同维护同一个count
  7. count++;
  8. }
  9. Point(Point &p) { //复制构造函数
  10. x = p.x;
  11. y = p.y;
  12. count++;
  13. }
  14. ~Point() { count--; }
  15. int getX() { return x; }
  16. int getY() { return y; }
  17. void showCount() { //输出静态数据成员
  18. cout << " Object count = " << count << endl;
  19. }
  20. private: //私有数据成员
  21. int x, y;
  22. static int count; //静态数据成员声明,用于记录点的个数
  23. };
  24. int Point::count = 0;//静态数据成员定义和初始化,使用类名限定
  25. int main() { //主函数
  26. Point a(4, 5); //定义对象a,其构造函数回使count增1
  27. cout << "Point A: " << a.getX() << ", " << a.getY();
  28. a.showCount(); //输出对象个数
  29. Point b(a); //定义对象b,其构造函数回使count增1
  30. cout << "Point B: " << b.getX() << ", " << b.getY();
  31. b.showCount(); //输出对象个数
  32. return 0;
  33. }

运行结果: Point A: 4, 5 Object count=1 Point B: 4, 5 Object count=2

类的静态函数成员

静态函数成员:类外代码可以使用类名和作用域操作符来调用静态成员函数。静态成员函数主要用于处理该类的静态数据成员,可以直接调用静态成员函数。如果访问非静态成员,要通过对象来访问。 例:具有静态数据、函数成员的 Point类

例:静态成员举例

 
  1. #include <iostream>
  2. using namespace std;
  3. class Point {
  4. public:
  5. Point(int x = 0, int y = 0) : x(x), y(y) { count++; }//构造函数
  6. Point(Point &p) { //复制构造函数
  7. x = p.x;
  8. y = p.y;
  9. count++;
  10. }
  11. ~Point() { count--; }
  12. int getX() { return x; }
  13. int getY() { return y; }
  14. static void showCount() {
  15. cout << " Object count = " << count << endl;
  16. }
  17. private:
  18. int x, y;
  19. static int count; //静态数据成员声明,用于记录点的个数
  20. };
  21. int Point::count = 0;//静态数据成员定义和初始化,使用类名限定
  22. int main() {
  23. Point::showCount();//输出对象个数
  24. Point a(4, 5); //定义对象a,其构造函数回使count增1
  25. cout << "Point A: " << a.getX() << ", " << a.getY();
  26. a.showCount(); //输出对象个数
  27. Point b(a); //定义对象b,其构造函数回使count增1
  28. cout << "Point B: " << b.getX() << ", " << b.getY();
  29. Point::showCount();//输出对象个数
  30. return 0;
  31. }
类的友元
  • 友元是C++提供的一种破坏数据封装和数据隐藏的机制;
  • 通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息;
  • 可以使用友元函数和友元类;
  • 为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元。
友元函数
  • 友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问 private 和 protected成员;
  • 作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择;
  • 访问对象中的成员必须通过对象名。

例: 使用友元函数计算两点间的距离

 
  1. #include <iostream>
  2. #include <cmath>
  3. class Point { //Point类声明
  4. public: //外部接口
  5. Point(int x=0, int y=0) : x(x), y(y) { }
  6. int getX() { return x; }
  7. int getY() { return y; }
  8. friend float dist(Point &a, Point &b);
  9. private: //私有数据成员
  10. int x, y;
  11. };
  12. float dist( Point& a, Point& b) {
  13. double x = a.x - b.x;
  14. double y = a.y - b.y;
  15. return static_cast<float>(sqrt(x * x + y * y));
  16. }
  17. int main() {
  18. Point p1(1, 1), p2(4, 5);
  19. cout <<"The distance is: ";
  20. cout << dist(p1, p2) << endl;
  21. return 0;
  22. }

运行结果: The distance is: 5

友元类
  • 若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员;
  • 声明语法:将友元类名在另一个类中使用friend修饰说明。
类的友元关系是单向的

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

任务要求

编写出实现客户机(CLIENT)类的代码,并将代码补充在右侧任务挑战区 Begin-End 之间。

测试说明

平台会对你编写的代码进行测试,请依次在平台上输入程序的输出:

预期输入:无 预期输出:程序实际的输出为准

代码
#include "client.h"

void Client::ChangeServerName(char name) {
    /********** Begin **********/
    ServerName = name;
    ClientNum++;
    /********** End **********/

}
int Client::getClientNum() {
    /********** Begin **********/
    return ClientNum;
    /********** End **********/
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小柒_02

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值