OOP-实验2

实验任务1

源代码task1

 1 // 类T的声明、友元函数声明
 2 
 3 #pragma once
 4 
 5 #include <string>
 6 
 7 // 类T: 声明
 8 class T
 9 {
10     // 对象属性、方法
11 public:
12     T(int x = 0, int y = 0); // 普通构造函数
13     T(const T &t);           // 复制构造函数
14     T(T &&t);                // 移动构造函数
15     ~T();                    // 析构函数
16 
17     void adjust(int ratio); // 按系数成倍调整数据
18     void display() const;   // 以(m1, m2)形式显示T类对象信息
19 
20 private:
21     int m1, m2;
22 
23     // 类属性、方法
24 public:
25     static int get_cnt(); // 显示当前T类对象总数
26 
27     static const std::string doc; // 类T的描述信息
28     static const int max_cnt;     // 类T对象上限
29 
30 private:
31     static int cnt; // 当前类T对象数目
32 
33     friend void func(); // 类T友元函数声明
34 };
35 
36 // 普通函数声明
37 void func();
38 
39 const std::string T::doc{"a simple class sample"};
40 const int T::max_cnt = 999;
41 int T::cnt = 0;
T.h
 1 // 类T的实现、友元函数实现
 2 
 3 #include "T.h"
 4 #include <iostream>
 5 #include <string>
 6 
 7 // 类T实现
 8 
 9 // static成员数据类外初始化
10 
11 
12 // 类方法
13 int T::get_cnt()
14 {
15     return cnt;
16 }
17 
18 // 对象方法
19 T::T(int x, int y) : m1{x}, m2{y}
20 {
21     cnt++;
22     std::cout << "T constructor called." << std::endl;
23 }
24 
25 T::T(const T &t) : m1{t.m1}, m2{t.m2}
26 {
27     cnt++;
28     std::cout << "T copy constructor called." << std::endl;
29 }
30 
31 T::T(T &&t) : m1{t.m1}, m2{t.m2}
32 {
33     cnt++;
34     std::cout << "T move constructor called." << std::endl;
35 }
36 
37 T::~T()
38 {
39     cnt--;
40     std::cout << "T destructor called." << std::endl;
41 }
42 
43 void T::adjust(int ratio)
44 {
45     m1 *= ratio;
46     m2 *= ratio;
47 }
48 
49 void T::display() const
50 {
51     std::cout << "(" << m1 << ", " << m2 << ")";
52 }
53 
54 // 普通函数实现
55 void func()
56 {
57     T t5(42);
58     t5.m2 = 2049;
59     std::cout << "t5 = ";
60     t5.display();
61     std::cout << std::endl;
62     std::cout << "func: T objects' current count: " << T::get_cnt() << std::endl;
63 }
T.cpp
 1 // 简单类T的定义和测试
 2 // 测试模块、main函数
 3 
 4 #include "T.h"
 5 #include <iostream>
 6 #include <string>
 7 
 8 // 测试函数声明
 9 void test_T();
10 
11 int main()
12 {
13     std::cout << "test Class T: " << std::endl;
14     test_T();
15 
16     std::cout << std::endl;
17     std::cout << "test friend func: " << std::endl;
18     func();
19 }
20 
21 void test_T()
22 {
23     using namespace std;
24 
25     cout << "T info: " << T::doc << endl;
26     cout << "T objects'max count: " << T::max_cnt << endl;
27     cout << "T objects'current count: " << T::get_cnt() << endl;
28     cout << endl;
29 
30     T t1;
31     cout << "t1 = ";
32     t1.display();
33     cout << endl;
34 
35     T t2(3, 4);
36     cout << "t2 = ";
37     t2.display();
38     cout << endl;
39 
40     T t3(t2);
41     t3.adjust(2);
42     cout << "t3 = ";
43     t3.display();
44     cout << endl;
45 
46     T t4(std::move(t2));
47     cout << "t4 = ";
48     t4.display();
49     cout << endl;
50 
51     cout << "test: T objects'current count: " << T::get_cnt() << endl;
52 }
task1.cpp

运行测试截图

task1

回答问题

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

屏幕截图 2025-10-22 090052

不能;

原因:此时友元函数func只在类内进行了声明,而在类外是不可见的;因此如果想要在类外使用它就必须另外在类外声明。

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

默认构造函数:(1)功能:调用时无须提供参数;如果类中没有写构造函数,编译器会自动生成一个隐含的默认构造函数,该构造函数的参数列表和函数体皆为空,无法赋初值;如果类中已声明了任意的构造函数(无论是否有参数),编译器都不会再为之生成隐含的构造函数。(2)调用时机:当以不带任何参数的形式创建对象时

普通构造函数:(1)功能:用已给定的参数来初始化对象。(2)调用时机:当以带参数的形式创建对象时

复制构造函数:(1)功能:用同一类的另一个对象来初始化本对象。(2)调用时机:当用同类的一个对象初始化另一个新对象时

移动构造函数:(1)功能:右值引用同类的另一个对象来初始化新对象。(2)调用时机:当使用右值引用来初始化新对象时

析构函数:(1)功能:释放对象所占的内存及完成相关的“清理”工作。(2)调用时机:在对象生存期结束时由编译器自动调用

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

屏幕截图 2025-10-22 212630

不能;

原因:将对 static 成员数据的初始化定义在 T.h 中,而 T.h 又被 T.cpp、task1.cpp 包含,因此相当于静态成员数据被多次定义,多重定义导致程序无法正确编译。

 

实验任务2

源代码task2

 1 #include <string>
 2 
 3 class Complex
 4 {
 5     // 类属性、方法
 6 public:
 7     static const std::string doc;
 8 
 9     // 对象属性、方法
10 public:
11     Complex(double real = 0.0, double imag = 0.0);
12     Complex(const Complex &c);
13 
14     double get_real() const;
15     double get_imag() const;
16     void add(const Complex &c);
17 
18 private:
19     double real, imag;
20 
21     // 友元函数
22     friend void output(const Complex &c);
23     friend double abs(const Complex &c);
24     friend Complex add(const Complex &c1, const Complex &c2);
25     friend bool is_equal(const Complex &c1, const Complex &c2);
26     friend bool is_not_equal(const Complex &c1, const Complex &c2);
27 };
28 
29 // 友元函数声明
30 void output(const Complex &c);
31 double abs(const Complex &c);
32 Complex add(const Complex &c1, const Complex &c2);
33 bool is_equal(const Complex &c1, const Complex &c2);
34 bool is_not_equal(const Complex &c1, const Complex &c2);
Complex.h
 1 #include "Complex.h"
 2 #include <iostream>
 3 #include <cmath>
 4 
 5 // 类属性、方法实现
 6 const std::string Complex::doc{"a simplified complex class"};
 7 
 8 // 对象方法实现
 9 Complex::Complex(double real, double imag) : real{real}, imag{imag} {}
10 
11 Complex::Complex(const Complex &c) : real{c.real}, imag{c.imag} {}
12 
13 double Complex::get_real() const
14 {
15     return real;
16 }
17 
18 double Complex::get_imag() const
19 {
20     return imag;
21 }
22 
23 void Complex::add(const Complex &c)
24 {
25     real += c.real;
26     imag += c.imag;
27 }
28 
29 // 友元函数实现
30 void output(const Complex &c)
31 {
32     if (c.imag >= 0)
33         std::cout << c.get_real() << " + " << c.get_imag() << "i";
34     else
35         std::cout << c.get_real() << " - " << c.get_imag() * (-1.0) << "i";
36 }
37 
38 double abs(const Complex &c)
39 {
40     return std::sqrt(c.get_real() * c.get_real() + c.get_imag() * c.get_imag());
41 }
42 
43 Complex add(const Complex &c1, const Complex &c2)
44 {
45     Complex c;
46     c.real = c1.real + c2.real;
47     c.imag = c1.imag + c2.imag;
48 
49     return c;
50 }
51 
52 bool is_equal(const Complex &c1, const Complex &c2)
53 {
54     if (c1.real == c2.real && c1.imag == c2.imag)
55         return true;
56     return false;
57 }
58 
59 bool is_not_equal(const Complex &c1, const Complex &c2)
60 {
61     if (is_equal(c1, c2))
62         return false;
63     return true;
64 }
Complex.cpp
  1 // 不适用C++标准库提供的复数模板类,设计并实现一个简化版复数类Complex
  2 
  3 #ifdef _WIN32
  4 #include <windows.h>
  5 #endif
  6 
  7 #include "Complex.h"
  8 #include <iostream>
  9 #include <iomanip>
 10 #include <complex>
 11 
 12 void test_Complex();
 13 void test_std_complex();
 14 void setConsoleUTF8()
 15 {
 16 #ifdef _WIN32
 17     SetConsoleOutputCP(65001);
 18     SetConsoleCP(65001);
 19 #endif
 20 }
 21 
 22 int main()
 23 {
 24     setConsoleUTF8();
 25     
 26     std::cout << "*******测试1: 自定义类Complex*******" << std::endl;
 27     test_Complex();
 28 
 29     std::cout << std::endl;
 30     std::cout << "*******测试2: 标准库模板类complex*******" << std::endl;
 31     test_std_complex();
 32 }
 33 
 34 void test_Complex()
 35 {
 36     using namespace std;
 37 
 38     cout << "类成员测试: " << endl;
 39     cout << Complex::doc << endl
 40          << endl;
 41 
 42     cout << "Complex对象测试: " << endl;
 43     Complex c1;
 44     Complex c2(3, -4);
 45     Complex c3(c2);
 46     Complex c4 = c2;
 47     const Complex c5(3.5);
 48 
 49     cout << "c1 = ";
 50     output(c1);
 51     cout << endl;
 52 
 53     cout << "c2 = ";
 54     output(c2);
 55     cout << endl;
 56 
 57     cout << "c3 = ";
 58     output(c3);
 59     cout << endl;
 60 
 61     cout << "c4 = ";
 62     output(c4);
 63     cout << endl;
 64 
 65     cout << "c5.real = " << c5.get_real()
 66          << ", c5.imag = " << c5.get_imag() << endl
 67          << endl;
 68 
 69     cout << "复数运算测试: " << endl;
 70 
 71     cout << "abs(c2) = " << abs(c2) << endl;
 72 
 73     c1.add(c2);
 74     cout << "c1 += c2, c1 = ";
 75     output(c1);
 76     cout << endl;
 77 
 78     cout << boolalpha;
 79     cout << "c1 == c2 : " << is_equal(c1, c2) << endl;
 80     cout << "c1 != c2 : " << is_not_equal(c1, c2) << endl;
 81 
 82     c4 = add(c2, c3);
 83     cout << "c4 = c2 + c3, c4 = ";
 84     output(c4);
 85     cout << endl;
 86 }
 87 
 88 void test_std_complex()
 89 {
 90     using namespace std;
 91 
 92     cout << "std::complex<double>对象测试: " << endl;
 93     std::complex<double> c1;
 94     std::complex<double> c2(3, -4);
 95     std::complex<double> c3(c2);
 96     std::complex<double> c4 = c2;
 97     const std::complex<double> c5(3.5);
 98 
 99     cout << "c1 = " << c1 << endl;
100     cout << "c2 = " << c2 << endl;
101     cout << "c3 = " << c3 << endl;
102     cout << "c4 = " << c4 << endl;
103 
104     cout << "c5.real = " << c5.real()
105          << ", c5.imag = " << c5.imag() << endl
106          << endl;
107 
108     cout << "复数运算测试: " << endl;
109     cout << "abs(c2) = " << abs(c2) << endl;
110     c1 += c2;
111     cout << "c1 += c2, c1 = " << c1 << endl;
112     cout << boolalpha;
113     cout << "c1 == c2 : " << (c1 == c2) << endl;
114     cout << "c1 != c2 : " << (c1 != c2) << endl;
115     c4 = c2 + c3;
116     cout << "c4 = c2 + c3, c4 = " << c4 << endl;
117 }
task2.cpp

运行测试截图

task2

回答问题

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

标准库模板类 complex 更简洁;

函数和运算内在是等价的

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

不需要;

理由:output/abs/add 函数的参数都是一个 Complex 类的对象,当我们需要使用该对象的私有数据时,我们可以通过它的成员函数 get_real() 和 get_imag() 获取,没有必要直接访问私有数据,这样还破坏了类的封装性和隐藏性

问题2-2:标准库 std::complex 是否把 abs 设为友元?

问题2-3:什么时候才考虑使用 friend ? 总结你的思考。

使用公有接口会导致较大的性能开销时;当运算符需要在左右操作数上有对称的访问权限时

问题3:如果构造对象时禁用 = 形式,即遇到 Complex c4 = c2; 编译报错,类 Complex 的设计应如何调整?

此时禁用了复制构造函数的隐式拷贝,可以选择复制构造函数的显式拷贝,如 Complex c4(c2);

 

实验任务3

源代码task3

 1 // 播放控制类PlayerControl声明
 2 
 3 #pragma once
 4 
 5 #include <string>
 6 
 7 enum class ControlType
 8 {
 9     Play,
10     Pause,
11     Next,
12     Prev,
13     Stop,
14     Unknown
15 };
16 
17 class PlayerControl
18 {
19 public:
20     PlayerControl();
21 
22     // 实现std::string --> ControlType转换
23     ControlType parse(const std::string &control_str);
24     void execute(ControlType cmd) const; // 执行控制操作(以打印输出模拟)
25 
26     static int get_cnt();
27 
28 private:
29     static int total_cnt;
30 };
PlayerControl.h
 1 // 播放控制类PlayerControl实现
 2 
 3 #include "PlayerControl.h"
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cctype>
 7 
 8 int PlayerControl::total_cnt = 0;
 9 
10 PlayerControl::PlayerControl() {}
11 
12 ControlType PlayerControl::parse(const std::string &control_str)
13 {
14     using namespace std;
15 
16     string control_str_trans;
17 
18     // 将control_str全部转为小写
19     for (auto &c : control_str)
20     {
21         char t = tolower(c);
22         control_str_trans += t;
23     }
24 
25     if (control_str_trans == "play")
26     {
27         total_cnt++;
28         return ControlType::Play;
29     }
30 
31     else if (control_str_trans == "pause")
32     {
33         total_cnt++;
34         return ControlType::Pause;
35     }
36 
37     else if (control_str_trans == "next")
38     {
39         total_cnt++;
40         return ControlType::Next;
41     }
42 
43     else if (control_str_trans == "prev")
44     {
45         total_cnt++;
46         return ControlType::Prev;
47     }
48 
49     else if (control_str_trans == "stop")
50     {
51         total_cnt++;
52         return ControlType::Stop;
53     }
54 
55     else
56         return ControlType::Unknown;
57 }
58 
59 void PlayerControl::execute(ControlType cmd) const
60 {
61     switch (cmd)
62     {
63     case ControlType::Play:
64         std::cout << "🎵 Playing music..." << std::endl;
65         break;
66 
67     case ControlType::Pause:
68         std::cout << "[Pause] Music paused." << std::endl;
69         break;
70 
71     case ControlType::Next:
72         std::cout << "[Next] Skipping to next track." << std::endl;
73         break;
74 
75     case ControlType::Prev:
76         std::cout << "[Prev] Back to previous track." << std::endl;
77 
78     case ControlType::Stop:
79         std::cout << "[Stop] Music stopped." << std::endl;
80         break;
81 
82     default:
83         std::cout << "[Error] unknown control." << std::endl;
84         break;
85     }
86 }
87 
88 int PlayerControl::get_cnt()
89 {
90     return total_cnt;
91 }
PlayerControl.cpp
 1 // 测试模块 + main
 2 
 3 #include "PlayerControl.h"
 4 #include <iostream>
 5 
 6 void test()
 7 {
 8     PlayerControl controller;
 9     std::string control_str;
10     std::cout << "Enter Control: (play/pause/next/prev/stop/quit): " << std::endl;
11 
12     while (std::cin >> control_str)
13     {
14         if (control_str == "quit")
15             break;
16 
17         ControlType cmd = controller.parse(control_str);
18         controller.execute(cmd);
19         std::cout << "Current Player control: " << PlayerControl::get_cnt() << std::endl
20                   << std::endl;
21     }
22 }
23 
24 int main()
25 {
26     test();
27     return 0;
28 }
task3.cpp

控制台输出 emoji :添加 UTF8 编码代码

 1 // 播放控制类PlayerControl声明
 2 
 3 #pragma once
 4 
 5 #include <string>
 6 
 7 enum class ControlType
 8 {
 9     Play,
10     Pause,
11     Next,
12     Prev,
13     Stop,
14     Unknown
15 };
16 
17 class PlayerControl
18 {
19 public:
20     PlayerControl();
21 
22     // 实现std::string --> ControlType转换
23     ControlType parse(const std::string &control_str);
24     void execute(ControlType cmd) const; // 执行控制操作(以打印输出模拟)
25 
26     static int get_cnt();
27 
28 private:
29     static int total_cnt;
30 };
PlayerControl.h
 1 // 播放控制类PlayerControl实现
 2 
 3 #include "PlayerControl.h"
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cctype>
 7 
 8 int PlayerControl::total_cnt = 0;
 9 
10 PlayerControl::PlayerControl() {}
11 
12 ControlType PlayerControl::parse(const std::string &control_str)
13 {
14     using namespace std;
15 
16     string control_str_trans;
17 
18     // 将control_str全部转为小写
19     for (auto &c : control_str)
20     {
21         char t = tolower(c);
22         control_str_trans += t;
23     }
24 
25     if (control_str_trans == "play")
26     {
27         total_cnt++;
28         return ControlType::Play;
29     }
30 
31     else if (control_str_trans == "pause")
32     {
33         total_cnt++;
34         return ControlType::Pause;
35     }
36 
37     else if (control_str_trans == "next")
38     {
39         total_cnt++;
40         return ControlType::Next;
41     }
42 
43     else if (control_str_trans == "prev")
44     {
45         total_cnt++;
46         return ControlType::Prev;
47     }
48 
49     else if (control_str_trans == "stop")
50     {
51         total_cnt++;
52         return ControlType::Stop;
53     }
54 
55     else
56         return ControlType::Unknown;
57 }
58 
59 void PlayerControl::execute(ControlType cmd) const
60 {
61     switch (cmd)
62     {
63     case ControlType::Play:
64         std::cout << "🎵 Playing music..." << std::endl;
65         break;
66 
67     case ControlType::Pause:
68         std::cout << "⏸ Music paused." << std::endl;
69         break;
70 
71     case ControlType::Next:
72         std::cout << "⏭ Skipping to next track." << std::endl;
73         break;
74 
75     case ControlType::Prev:
76         std::cout << "⏮ Back to previous track." << std::endl;
77         break;
78 
79     case ControlType::Stop:
80         std::cout << "⏹ Music stopped." << std::endl;
81         break;
82 
83     default:
84         std::cout << "❌ unknown control." << std::endl;
85         break;
86     }
87 }
88 
89 int PlayerControl::get_cnt()
90 {
91     return total_cnt;
92 }
PlayerControl.cpp
 1 // 测试模块 + main
 2 
 3 #ifdef _WIN32
 4 #include <windows.h>
 5 #endif
 6 
 7 #include "PlayerControl.h"
 8 #include <iostream>
 9 
10 void setConsoleUTF8()
11 {
12 #ifdef _WIN32
13     SetConsoleOutputCP(65001);
14     SetConsoleCP(65001);
15 #endif
16 }
17 
18 void test()
19 {
20     PlayerControl controller;
21     std::string control_str;
22     std::cout << "Enter Control: (play/pause/next/prev/stop/quit): " << std::endl;
23 
24     while (std::cin >> control_str)
25     {
26         if (control_str == "quit")
27             break;
28 
29         ControlType cmd = controller.parse(control_str);
30         controller.execute(cmd);
31         std::cout << "Current Player control: " << PlayerControl::get_cnt() << std::endl
32                   << std::endl;
33     }
34 }
35 
36 int main()
37 {
38     setConsoleUTF8();
39     test();
40     return 0;
41 }
task3.cpp

运行测试截图

task3

屏幕截图 2025-10-23 155600

 

实验任务4

源代码task4

 1 #pragma once
 2 
 3 #include <string>
 4 
 5 class Fraction
 6 {
 7     // 类属性
 8 public:
 9     static const std::string doc;
10 
11     // 对象属性、方法
12 public:
13     Fraction(int up, int down = 1);
14     Fraction(const Fraction &f);
15 
16     int get_up() const;
17     int get_down() const;
18     Fraction negative();
19 
20 private:
21     int up, down;
22 };
23 
24 // 工具函数
25 namespace Utils
26 {
27     void output(const Fraction &f);
28     Fraction add(const Fraction &f1, const Fraction &f2);
29     Fraction sub(const Fraction &f1, const Fraction &f2);
30     Fraction mul(const Fraction &f1, const Fraction &f2);
31     Fraction div(const Fraction &f1, const Fraction &f2);
32     Fraction trans(Fraction &f);
33 }
Fraction.h
  1 #include "Fraction.h"
  2 #include <iostream>
  3 #include <string>
  4 #include <cmath>
  5 
  6 const std::string Fraction::doc{
  7     "Fraction类 v 0.01版.\n"
  8     "目前仅支持分数对象的构造、输出、加/减/乘/除运算."}; // 字符串中间不能直接换行
  9 
 10 Fraction::Fraction(int up, int down) : up{up}, down{down} {}
 11 
 12 Fraction::Fraction(const Fraction &f) : up{f.up}, down{f.down} {}
 13 
 14 int Fraction::get_up() const
 15 {
 16     return up;
 17 }
 18 
 19 int Fraction::get_down() const
 20 {
 21     return down;
 22 }
 23 
 24 Fraction Fraction::negative()
 25 {
 26     return Fraction(-up, down);
 27 }
 28 
 29 void Utils::output(const Fraction &f)
 30 {
 31     int up = f.get_up();
 32     int down = f.get_down();
 33 
 34     if (down == 0)
 35     {
 36         std::cout << "分母不能为0" << std::endl;
 37         return;
 38     }
 39 
 40     if (down == 1)
 41     {
 42         std::cout << up;
 43         return;
 44     }
 45 
 46     if (up == 0)
 47     {
 48         std::cout << up;
 49         return;
 50     }
 51 
 52     int a = abs(f.get_up());
 53     int b = abs(f.get_down());
 54     // 求最大公约数
 55     while (b != 0)
 56     {
 57         int t = b;
 58         b = a % b;
 59         a = t;
 60     }
 61     up /= a;
 62     down /= a;
 63 
 64     if (down < 0)
 65     {
 66         up = -up;
 67         down = -down;
 68     }
 69 
 70     std::cout << up << "/" << down;
 71 }
 72 
 73 Fraction Utils::add(const Fraction &f1, const Fraction &f2)
 74 {
 75     int down = f1.get_down() * f2.get_down();
 76     int up = f1.get_up() * f2.get_down() + f2.get_up() * f1.get_down();
 77 
 78     return Fraction(up, down);
 79 }
 80 
 81 Fraction Utils::sub(const Fraction &f1, const Fraction &f2)
 82 {
 83     int down = f1.get_down() * f2.get_down();
 84     int up = f1.get_up() * f2.get_down() - f2.get_up() * f1.get_down();
 85 
 86     return Fraction(up, down);
 87 }
 88 
 89 Fraction Utils::mul(const Fraction &f1, const Fraction &f2)
 90 {
 91     int up = f1.get_up() * f2.get_up();
 92     int down = f1.get_down() * f2.get_down();
 93 
 94     return Fraction(up, down);
 95 }
 96 
 97 Fraction Utils::div(const Fraction &f1, const Fraction &f2)
 98 {
 99     int up = f1.get_up() * f2.get_down();
100     int down = f1.get_down() * f2.get_up();
101 
102     return Fraction(up, down);
103 }
104 
105 Fraction Utils::trans(Fraction &f)
106 {
107     int up = f.get_up();
108     int down = f.get_down();
109     int a = abs(f.get_up());
110     int b = abs(f.get_down());
111     // 求最大公约数
112     while (b != 0)
113     {
114         int t = b;
115         b = a % b;
116         a = t;
117     }
118     up /= a;
119     down /= a;
120 
121     return Fraction(up, down);
122 }
Fraction.cpp
  1 #include "Fraction.h"
  2 #include <iostream>
  3 
  4 #ifdef _WIN32
  5 #include <windows.h>
  6 #endif
  7 
  8 void test1();
  9 void test2();
 10 void setConsoleUTF8()
 11 {
 12 #ifdef _WIN32
 13     SetConsoleOutputCP(65001);
 14     SetConsoleCP(65001);
 15 #endif
 16 }
 17 
 18 int main()
 19 {
 20     setConsoleUTF8();
 21     
 22     std::cout << "测试1: Fraction类基础功能测试" << std::endl;
 23     test1();
 24 
 25     std::cout << std::endl;
 26     std::cout << "测试2: 分母为0测试: " << std::endl;
 27     test2();
 28 }
 29 
 30 void test1()
 31 {
 32     using namespace std;
 33 
 34     cout << "Fraction类测试: " << endl;
 35     cout << Fraction::doc << endl
 36          << endl;
 37 
 38     Fraction f1(5);
 39     Fraction f2(3, -4), f3(-18, 12);
 40     Fraction f4(f3);
 41 
 42     cout << "f1 = ";
 43     Utils::output(f1);
 44     cout << endl;
 45 
 46     cout << "f2 = ";
 47     Utils::output(f2);
 48     cout << endl;
 49 
 50     cout << "f3 = ";
 51     Utils::output(f3);
 52     cout << endl;
 53 
 54     cout << "f4 = ";
 55     Utils::output(f4);
 56     cout << endl;
 57 
 58     Fraction f5(f4.negative());
 59     cout << "f5 = ";
 60     Utils::output(f5);
 61     cout << endl;
 62 
 63     f5 = Utils::trans(f5);
 64     cout << "f5.get_up() = " << f5.get_up()
 65          << ", f5.get_down() = " << f5.get_down() << endl;
 66 
 67     cout << "f1 + f2 = ";
 68     Utils::output(Utils::add(f1, f2));
 69     cout << endl;
 70 
 71     cout << "f1 - f2 = ";
 72     Utils::output(Utils::sub(f1, f2));
 73     cout << endl;
 74 
 75     cout << "f1 * f2 = ";
 76     Utils::output(Utils::mul(f1, f2));
 77     cout << endl;
 78 
 79     cout << "f1 / f2 = ";
 80     Utils::output(Utils::div(f1, f2));
 81     cout << endl;
 82 
 83     cout << "f4 + f5 = ";
 84     Utils::output(Utils::add(f4, f5));
 85     cout << endl;
 86 }
 87 
 88 void test2()
 89 {
 90     using namespace std;
 91 
 92     Fraction f6(42, 55), f7(0, 3);
 93 
 94     cout << "f6 = ";
 95     Utils::output(f6);
 96     cout << endl;
 97 
 98     cout << "f7 = ";
 99     Utils::output(f7);
100     cout << endl;
101 
102     cout << "f6 / f7 = ";
103     Utils::output(Utils::div(f6, f7));
104     cout << endl;
105 }
task4.cpp

运行测试截图

task4

回答问题

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

选择的是 命名空间 + 自由函数

理由:友元方案会破坏类的封装性和隐藏性;静态成员函数方案会使类内有过多的函数方法,且不利于后续的扩展和维护;命名空间方案扩展性和维护性好,且更有利于团队协作

 

实验总结

1. 即使在类内声明了友元函数,在类外还要再声明一次,写在 X.h 文件里即可

2. 采用多文件结构时,静态数据成员的类外初始化不能写在 X.h 里,会导致多重定义,应该写在 X.cpp 里

3. 当控制台输出中文时显示乱码时,解决方法:

 1 // task.cpp
 2 
 3 #ifdef _WIN32
 4 #include <windows.h>
 5 #endif
 6 
 7 void setConsoleUTF8()
 8 {
 9 #ifdef _WIN32
10     SetConsoleOutputCP(65001);
11     SetConsoleCP(65001);
12 #endif
13 }
14 
15 int main()
16 {
17     setConsoleUTF8();
18 }
Encoding

4. 字符串中间不能直接换行,应该自换行处分开为多个字符串:

const std::string Fraction::doc{
    "Fraction类 v 0.01版.\n"
    "目前仅支持分数对象的构造、输出、加/减/乘/除运算."}; 
posted @ 2025-10-23 16:25  FF-10086  阅读(25)  评论(0)    收藏  举报