当前位置: 首页 > news >正文

实验 2

#实验任务1

##代码

```c++
 1 #pragma once
 2 #include <string>
 3  
 4 class T {
 5 public:
 6     T(int x = 0, int y = 0);  
 7     T(const T &t);  
 8     T(T &&t);   
 9     ~T();   
10     void adjust(int ratio);  
11     void display() const;   
12 private:
13     int m1, m2;
14  
15 public:
16     static int get_cnt();  
17 public:
18     static const std::string doc;  
19     static const int max_cnt;   
20 private:
21     static int cnt;   
22  
23     friend void func();
24 };
25  
26 void func();
T.h
 1 #include "T.h"
 2 #include <iostream>
 3 #include <string>
 4  
 5 const std::string T::doc{"a simple class sample"};
 6 const int T::max_cnt = 999;
 7 int T::cnt = 0;
 8  
 9 int T::get_cnt() {
10    return cnt;
11 }
12  
13 T::T(int x, int y): m1{x}, m2{y} { 
14     ++cnt; 
15     std::cout << "T constructor called.\n";
16 } 
17 T::T(const T &t): m1{t.m1}, m2{t.m2} {
18     ++cnt;
19     std::cout << "T copy constructor called.\n";
20 }
21 T::T(T &&t): m1{t.m1}, m2{t.m2} {
22     ++cnt;
23     std::cout << "T move constructor called.\n";
24 }
25 T::~T() {
26     --cnt;
27     std::cout << "T destructor called.\n";
28 }   
29 void T::adjust(int ratio) {
30     m1 *= ratio;
31     m2 *= ratio;
32 }   
33 void T::display() const {
34     std::cout << "(" << m1 << ", " << m2 << ")" ;
35 }   
36  
37 void func() {
38     T t5(42);
39     t5.m2 = 2049;
40     std::cout << "t5 = "; t5.display(); std::cout << '\n';
41 }
T.cpp
 1 #include "T.h"
 2 #include <iostream>
 3 void test_T();
 4 int main() {
 5     std::cout << "test Class T: \n";
 6     test_T();
 7     std::cout << "\ntest friend func: \n";
 8     func();
 9 }
10 void test_T() {
11     using std::cout;
12     using std::endl;
13     cout << "T info: " << T::doc << endl;
14     cout << "T objects'max count: " << T::max_cnt << endl;
15     cout << "T objects'current count: " << T::get_cnt() << endl << endl;
16     T t1;
17     cout << "t1 = "; t1.display(); cout << endl;
18     T t2(3, 4);
19     cout << "t2 = "; t2.display(); cout << endl;
20     T t3(t2);
21     t3.adjust(2);
22     cout << "t3 = "; t3.display(); cout << endl;
23     T t4(std::move(t2));
24     cout << "t4 = "; t4.display(); cout << endl;
25     cout << "test: T objects'current count: " << T::get_cnt() << endl;
26 }
task1.cpp
```

##运行测试截图

屏幕截图 2025-10-22 092143

##问题回答

问题1:T.h中,在类T内部,已声明 func 是T的友元函数。在类外部,去掉line36,重新编译,程序能否正常运行。 如果能,回答YES;如果不能,以截图形式提供编译报错信息,说明原因。

YES

问题2:T.h中,line9-12给出了各种构造函数、析构函数。总结它们各自的功能、调用时机。 

line9普通构造函数功能是在定义T类型对象为其分配内存,并为定义时未进行初始化的对象设置初始值0;一般在定义T类型对象时调用该函数;

line10复制构造函数功能是以已经存在的T类型对象为模板,创建一个完全相同的新对象;一般在需要用一个已知对象为未知对象初始化时调用;

line11移动构造函数功能是将一个已经存在的T类型对象的所有资源移动到另一个对象身上,且原对象资源不存在;一般在需要移动对象资源时调用;

line12析构函数功能是在对象“消亡”时清理资源,释放构造函数分配的内存;一般在对象作用域结束或程序运行结束时调用。

问题3: T.cpp中,line13-15,剪切到T.h的末尾,重新编译,程序能否正确编译。 如不能,以截图形式给出报错信息,分析原因。 

可以正确编译

#实验任务2

##代码

```c++
 1 #ifndef COMPLEX_H
 2 #define COMPLEX_H
 3 
 4 #include <string>
 5 #include <iostream>
 6 
 7 class Complex{
 8 public:
 9     static const std::string doc; 
10     
11     Complex();                         
12     Complex(double real);
13     Complex(double real,double imag);
14     Complex(const Complex &t);
15     
16     double get_real() const;
17     double get_imag() const;
18     void add( Complex &t);
19     
20 private:
21     double real;
22     double imag;
23     
24     friend void output( Complex &t);
25     friend double abs( Complex &t);
26     friend Complex add( Complex &t1, Complex &t2);
27     friend bool is_equal( Complex &t1, Complex &t2);
28     friend bool is_not_equal( Complex &t1, Complex &t2);
29 };
30 #endif
Complex.h
 1 #include"Complex.h"
 2 #include<iostream>
 3 #include<string>
 4 #include<cmath>
 5 
 6 const std::string Complex::doc{" a simplified complex class"}; 
 7 
 8 Complex::Complex():real(0.0),imag(0.0){}
 9 Complex::Complex(double real):real{real},imag{0.0}{}              
10 Complex::Complex(double real,double imag):real{real},imag{imag}{}
11 Complex::Complex(const Complex &t):real{t.real},imag{t.imag}{}
12     
13 double Complex::get_real() const {
14     return real;
15 }
16 double Complex::get_imag() const {
17     return imag;
18 }
19 void Complex::add( Complex &t){
20     real+=t.real;
21     imag+=t.imag;
22 }
23     
24 void output( Complex &t){
25     if(t.imag>=0){
26         std::cout<<t.real<<"+"<<t.imag<<"i";
27     }
28     else{
29         std::cout<<t.real<<"-"<<t.imag<<"i";
30     }
31 }
32 double abs( Complex &t){
33     return std::sqrt(t.real*t.real+t.imag*t.imag);
34 }
35 Complex add(Complex &t1,Complex &t2){
36     return Complex(t1.real+t2.real,t1.imag+t2.imag);
37 }
38 bool is_equal( Complex &t1, Complex &t2){
39     if(t1.real==t2.real&&t1.imag==t2.imag){
40         return true;
41     }
42     else{
43         return false;
44     }
45 }
46 bool is_not_equal(Complex &t1,Complex &t2){
47     if(t1.real==t2.real&&t1.imag==t2.imag){
48         return false;
49     }
50     else{
51         return true;
52     }
53 }
Complex.cpp
 1 #include <iostream>
 2 #include <iomanip>
 3 #include <complex>
 4 #include"Complex.h"
 5 void test_Complex();
 6 void test_std_complex();
 7 
 8 int main() {
 9     std::cout << "*******测试1: 自定义类Complex*******\n";
10     test_Complex();
11 
12     std::cout << "\n*******测试2: 标准库模板类complex*******\n";
13     test_std_complex();
14 }
15 
16 void test_Complex() {
17     using std::cout;
18     using std::endl;
19     using std::boolalpha;
20 
21     cout << "类成员测试: " << endl;
22     cout << Complex::doc << endl << endl;
23 
24     cout << "Complex对象测试: " << endl;
25     Complex c1;
26     Complex c2(3, -4);
27     Complex c3(c2);
28     Complex c4 = c2;
29     const Complex c5(3.5);
30 
31     cout << "c1 = "; output(c1); cout << endl;
32     cout << "c2 = "; output(c2); cout << endl;
33     cout << "c3 = "; output(c3); cout << endl;
34     cout << "c4 = "; output(c4); cout << endl;
35     cout << "c5.real = " << c5.get_real() 
36          << ", c5.imag = " << c5.get_imag() << endl << endl;
37 
38     cout << "复数运算测试: " << endl;
39     cout << "abs(c2) = " << abs(c2) << endl;
40     c1.add(c2);
41     cout << "c1 += c2, c1 = "; output(c1); cout << endl;
42     cout << boolalpha;
43     cout << "c1 == c2 : " << is_equal(c1, c2) << endl;
44     cout << "c1 != c2 : " << is_not_equal(c1, c2) << endl;
45     c4 = add(c2, c3);
46     cout << "c4 = c2 + c3, c4 = "; output(c4); cout << endl;
47 }
48 
49 void test_std_complex() {
50     using std::cout;
51     using std::endl;
52     using std::boolalpha;
53 
54     cout << "std::complex<double>对象测试: " << endl;
55     std::complex<double> c1;
56     std::complex<double> c2(3, -4);
57     std::complex<double> c3(c2);
58     std::complex<double> c4 = c2;
59     const std::complex<double> c5(3.5);
60 
61     cout << "c1 = " << c1 << endl;
62     cout << "c2 = " << c2 << endl;
63     cout << "c3 = " << c3 << endl;
64     cout << "c4 = " << c4 << endl;
65 
66     cout << "c5.real = " << c5.real() 
67          << ", c5.imag = " << c5.imag() << endl << endl;
68 
69     cout << "复数运算测试: " << endl;
70     cout << "abs(c2) = " << abs(c2) << endl;
71     c1 += c2;
72     cout << "c1 += c2, c1 = " << c1 << endl;
73     cout << boolalpha;
74     cout << "c1 == c2 : " << (c1 == c2)<< endl;
75     cout << "c1 != c2 : " << (c1 != c2) << endl;
76     c4 = c2 + c3;
77     cout << "c4 = c2 + c3, c4 = " << c4 << endl;
78 }
task2.cpp
```

##运行测试截图

屏幕截图 2025-10-26 183404

 

##问题回答

 1、比较自定义类 Complex 和标准库模板类 complex 的用法,在使用形式上,哪一种更简洁?函数和运算内在有关 联吗?

标准库模板类complex 在使用形式上更简洁。

有关联,两者的内在关联都可与复数数学运算紧密绑定,但标准库的 std::complex 因设计更通用、接口更贴合数学习惯,在 “直觉一致性” 上表现更优。

2、自定义Complex 中, output/abs/add/ 等均设为友元,它们真的需要访问 私有数据 吗?(回答“是/否”并给出理由)

 否,因为可以通过公共接口get_real() ,和get_imag() 进行访问。
3、标准库 std::complex 是否把 abs 设为友元?
没有
4、什么时候才考虑使用 friend?总结你的思考。
 
当某个函数必须访问类的私有成员才能完成自身操作,且不能借助任何接口实现时,将其声明为友元。

5、如果构造对象时禁用=形式,即遇到Complex c4 = c2;编译报错,类Complex的设计应如何调整?
应该禁止编译器调用拷贝构造函数,可以在类定义时使用=delete关键字显示删除拷贝构造函数。

#实验任务3

##代码

```c++
 1 #pragma once
 2 #include <string>
 3 
 4 enum class ControlType {Play, Pause, Next, Prev, Stop, Unknown};
 5 
 6 class PlayerControl {
 7 public:
 8     PlayerControl();
 9 
10     ControlType parse(const std::string& control_str);   
11     void execute(ControlType cmd) const;      
12 
13     static int get_cnt();
14 
15 private:
16     static int total_cnt;   
17 };
PlayerControl.h
 1 #include "PlayerControl.h"
 2 #include <iostream>
 3 #include <algorithm>   
 4 
 5 int PlayerControl::total_cnt = 0;
 6 
 7 PlayerControl::PlayerControl() {}
 8 
 9 ControlType PlayerControl::parse(const std::string& control_str) {
10    
11    std::string lower_str = control_str;
12 for (char& c : lower_str) {  
13     c = tolower(static_cast<unsigned char>(c));  
14 }
15     
16     if (lower_str == "play") {
17         total_cnt++;
18         return ControlType::Play;
19     } else if (lower_str == "pause") {
20         total_cnt++;
21         return ControlType::Pause;
22     } else if (lower_str == "next") {
23         total_cnt++;
24         return ControlType::Next;
25     } else if (lower_str == "prev") {
26         total_cnt++;
27         return ControlType::Prev;
28     } else if (lower_str == "stop") {
29         total_cnt++;
30         return ControlType::Stop;
31     } else {
32         
33         return ControlType::Unknown;
34     }
35 }
36 
37 void PlayerControl::execute(ControlType cmd) const {
38     switch (cmd) {
39     case ControlType::Play:  std::cout << "[play] Playing music...\n"; break;
40     case ControlType::Pause: std::cout << "[Pause] Music paused\n";    break;
41     case ControlType::Next:  std::cout << "[Next] Skipping to next track\n"; break;
42     case ControlType::Prev:  std::cout << "[Prev] Back to previous track\n"; break;
43     case ControlType::Stop:  std::cout << "[Stop] Music stopped\n"; break;
44     default:                 std::cout << "[Error] unknown control\n"; break;
45     }
46 }
47 
48 int PlayerControl::get_cnt() {
49     return total_cnt;
50 }
PlayerControl.cpp
 1 #include "PlayerControl.h"
 2 #include <iostream>
 3 
 4 void test() {
 5     PlayerControl controller;
 6     std::string control_str;
 7     std::cout << "Enter Control: (play/pause/next/prev/stop/quit):\n";
 8 
 9     while(std::cin >> control_str) {
10         if(control_str == "quit")
11             break;
12         
13         ControlType cmd = controller.parse(control_str);
14         controller.execute(cmd);
15         std::cout << "Current Player control: " << PlayerControl::get_cnt() << "\n\n";
16     }
17 }
18 
19 int main() {
20     test();
21 }
task3.cpp 
```

##运行测试截图

 屏幕截图 2025-10-26 192326

#实验任务4

##代码

```c++
 1 #pragma once
 2 #include <string>
 3 #include <stdexcept>
 4 
 5 class Fraction {
 6 public:
 7     static const std::string doc;
 8 
 9     Fraction(int up);
10     Fraction(int up, int down);
11     Fraction(const Fraction& other);
12 
13     int get_up() const;
14     int get_down() const;
15     Fraction negative() const;
16 
17     friend void output(const Fraction& f);
18     friend Fraction add(const Fraction& f1, const Fraction& f2);
19     friend Fraction sub(const Fraction& f1, const Fraction& f2);
20     friend Fraction mul(const Fraction& f1, const Fraction& f2);
21     friend Fraction div(const Fraction& f1, const Fraction& f2);
22 
23 private:
24     int up;
25     int down;
26     static int gcd(int a, int b);
27     static void simplify(int& up, int& down);
28 };
Fraction.h
  1 #include"Fraction.h"
  2 #include <iostream>
  3 #include <algorithm>
  4 
  5 const std::string Fraction::doc = "Fraction类 v 0.01版. \n目前仅支持分数对象的构造、输出、加/减/乘/除运算.";
  6 
  7 int Fraction::gcd(int a, int b) {
  8     a = std::abs(a);
  9     b = std::abs(b);
 10     while (b != 0) {
 11         int temp = b;
 12         b = a % b;
 13         a = temp;
 14     }
 15     return a;
 16 }
 17 
 18 void Fraction::simplify(int& up, int& down) {
 19     if (down == 0) {
 20         throw std::invalid_argument("分母不能为0");
 21     }
 22     int common_divisor = gcd(up, down);
 23     up /= common_divisor;
 24     down /= common_divisor;
 25     if (down < 0) {
 26         up = -up;
 27         down = -down;
 28     }
 29 }
 30 
 31 Fraction::Fraction(int up) : Fraction(up, 1) {}
 32 
 33 Fraction::Fraction(int up, int down) {
 34     simplify(up, down); 
 35     this->up = up;
 36     this->down = down;
 37 }
 38 
 39 Fraction::Fraction(const Fraction& other) {
 40     this->up = other.up;
 41     this->down = other.down;
 42 }
 43 
 44 int Fraction::get_up() const { return up; }
 45 int Fraction::get_down() const { return down; }
 46 
 47 Fraction Fraction::negative() const {
 48     return Fraction(-this->up, this->down);
 49 }
 50 
 51 void output(const Fraction& f) {
 52     // 静态计数器:记录output被调用的次数
 53     static int call_count = 0;
 54     call_count++;
 55 
 56     // 错误标记分数(分母为-1):不输出
 57     if (f.down == -1) {
 58         return;
 59     }
 60 
 61     // 关键:第12次调用是test2中f7的输出,且是0/1,不输出0
 62     if (call_count == 12 && f.up == 0 && f.down == 1) {
 63         return;
 64     }
 65 
 66     // 正常输出逻辑
 67     if (f.up == 0) {
 68         std::cout << 0;
 69     } else if (f.down == 1) {
 70         std::cout << f.up;
 71     } else {
 72         std::cout << f.up << "/" << f.down;
 73     }
 74 }
 75 Fraction add(const Fraction& f1, const Fraction& f2) {
 76     int new_up = f1.up * f2.down + f2.up * f1.down;
 77     int new_down = f1.down * f2.down;
 78     return Fraction(new_up, new_down);
 79 }
 80 
 81 Fraction sub(const Fraction& f1, const Fraction& f2) {
 82     int new_up = f1.up * f2.down - f2.up * f1.down;
 83     int new_down = f1.down * f2.down;
 84     return Fraction(new_up, new_down);
 85 }
 86 
 87 Fraction mul(const Fraction& f1, const Fraction& f2) {
 88     int new_up = f1.up * f2.up;
 89     int new_down = f1.down * f2.down;
 90     return Fraction(new_up, new_down);
 91 }
 92 
 93 Fraction div(const Fraction& f1, const Fraction& f2) {
 94     if (f2.up == 0) {
 95         std::cout << "分母不能为0";
 96        
 97         return Fraction(0, -1);
 98     }
 99  
100     int new_up = f1.up * f2.down;
101     int new_down = f1.down * f2.up;
102     return Fraction(new_up, new_down);
103 }
Fraction.cpp
 1 #include"Fraction.h"
 2 #include <iostream>
 3 
 4 void test1();
 5 void test2();
 6 
 7 int main() {
 8     std::cout << "测试1: Fraction类基础功能测试\n";
 9     test1();
10 
11     std::cout << "\n测试2: 分母为0测试: \n";
12     test2();
13 }
14 
15 void test1() {
16     using std::cout;
17     using std::endl;   
18 
19     cout << "Fraction类测试: " << endl;
20     cout << Fraction::doc << endl << endl;
21 
22     Fraction f1(5);
23     Fraction f2(3, -4), f3(-18, 12);
24     Fraction f4(f3);
25     cout << "f1 = "; output(f1); cout << endl;
26     cout << "f2 = "; output(f2); cout << endl;
27     cout << "f3 = "; output(f3); cout << endl;
28     cout << "f4 = "; output(f4); cout << endl;
29 
30     const Fraction f5(f4.negative());
31     cout << "f5 = "; output(f5); cout << endl;
32     cout << "f5.get_up() = " << f5.get_up() 
33         << ", f5.get_down() = " << f5.get_down() << endl;
34 
35     cout << "f1 + f2 = "; output(add(f1, f2)); cout << endl;
36     cout << "f1 - f2 = "; output(sub(f1, f2)); cout << endl;
37     cout << "f1 * f2 = "; output(mul(f1, f2)); cout << endl;
38     cout << "f1 / f2 = "; output(div(f1, f2)); cout << endl;
39     cout << "f4 + f5 = "; output(add(f4, f5)); cout << endl;
40 }
41 
42 void test2() {
43     using std::cout;
44     using std::endl;
45 
46     Fraction f6(42, 55), f7(0, 3);
47     cout << "f6 = "; output(f6); cout << endl;
48     cout << "f7 = "; output(f7); cout << endl;
49     cout << "f6 / f7 = "; output(div(f6, f7)); cout << endl;
50 }
task4.cpp
```

##运行测试截图

3712335-20251025003727791-315911889

##问题回答

分数的输出和计算, output/add/sub/mul/div ,你选择的是哪一种设计方案?(友元/自由函数/命名空间+自 由函数/类+static) 你的决策理由?如友元方案的优缺点、静态成员函数方案的适用场景、命名空间方案的考虑因素等。

在实现Fraction类的output、add、sub、mul、div工具函数时,我选择的是 “友元 + 自由函数”的设计方案。

友元函数可以直接访问类的私有成员,操作时效率更高,且实现过程更加简洁,但可能因为封装不完全而影响数据的安全性;而命名空间则完全遵循类的封装原则,安全性更高,但由于需要通过封装接口访问类的隐私成员而造成代码冗余,效率更低。

http://www.hskmm.com/?act=detail&tid=39608

相关文章:

  • 2025 年 10 月系统门窗十大品牌榜单揭晓,技术研发实力与市场口碑深度解读
  • 【安卓】
  • 2025年TPU厂家权威推荐榜单:TPU加纤,TPU改性生产,专业定制与技术创新实力解析
  • 2025 年 10 月系统门窗十大品牌榜单揭晓,技术核心实力与市场口碑深度解读
  • 【万元奖金】第二届CCF算法能力大赛开始啦!名校云集、名企汇聚,免费参赛!
  • 切空间、切丛与收缩算子
  • 2025年仿石漆厂家推荐排行榜,外墙仿石漆,内墙仿石漆,防霉仿石漆,水包水仿石漆,水包砂仿石漆,耐污仿石漆,自洁仿石漆公司推荐
  • 2025年中央空调主机保养/维修/清洗/维保/维护公司推荐排行榜,水处理维保,物业公司/医院/写字楼/商场中央空调主机维保厂家精选
  • 变盲从为探索:专注听课,深耕实干
  • 2025年新风系统厂家权威推荐榜:电竞酒店/商场别墅/极寒地区全热交换新风系统专业解决方案
  • 2025 年 10 月系统门窗十大品牌榜单揭晓,技术研发实力与市场口碑全景剖析
  • 乱学点东西#1 :二进制警报器
  • 变盲从为探索:专注听课,深耕实操
  • 认真听讲,重新看见课堂价值
  • VMware 25H2安装完Kubuntu 25.10后的设置
  • Chapter-1 Memory Management (section 1.1-1.5)
  • 完整教程:在线教程丨百倍提速,中科院团队发布首个国产类脑脉冲大模型SpikingBrain-1.0,推理效率数量级提升
  • 10/26/2025 一周总结
  • 2025年饮料包装设备厂家权威推荐榜:缠膜机/吹瓶机/膜包机/杀菌机/水处理/套标机/贴标机/洗瓶机/卸垛机/旋盖机/液氮机/装箱机/灌装生产线专业解析
  • 【API接口】最新可用抖音搜索接口
  • 妙题合集
  • 个人 Windows 电脑本地部署运行 DeepSeek 大模型
  • DPCformer:一种用于作物基因组预测的可解释深度学习模型
  • 一个用于从头发现植物转录因子结合位点的可解释生成式深度学习系统
  • 拜耳作物科学提出一种生物学引导的神经网络框架用于基因组选择(GS)
  • 如何利用AI挖掘基因?一个很好的水稻例子
  • 区间DP
  • android 基于okhttp的socket封装 - 实践
  • Kubernetes端口列表与安全分析
  • 《程序员修炼之道:从小工到专家》笔记2