实验二
1、实验任务1:
T.h源代码:
1 #pragma once 2 3 #include <string> 4 5 class T { 6 7 public: 8 T(int x = 0, int y = 0); 9 T(const T &t); 10 T(T &&t); 11 ~T(); 12 13 void adjust(int ratio); 14 void display() const; 15 16 private: 17 int m1, m2; 18 19 public: 20 static int get_cnt(); 21 22 public: 23 static const std::string doc; 24 static const int max_cnt; 25 26 private: 27 static int cnt; 28 29 friend void func(); 30 }; 31 32 void func();
T.cpp源代码:
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 18 T::T(const T &t): m1{t.m1}, m2{t.m2} { 19 ++cnt; 20 std::cout << "T copy constructor called.\n"; 21 } 22 23 T::T(T &&t): m1{t.m1}, m2{t.m2} { 24 ++cnt; 25 std::cout << "T move constructor called.\n"; 26 } 27 28 T::~T() { 29 --cnt; 30 std::cout << "T destructor called.\n"; 31 } 32 33 void T::adjust(int ratio) { 34 m1 *= ratio; 35 m2 *= ratio; 36 } 37 38 void T::display() const { 39 std::cout << "(" << m1 << ", " << m2 << ")" ; 40 } 41 42 void func() { 43 T t5(42); 44 t5.m2 = 2049; 45 std::cout << "t5 = "; t5.display(); std::cout << '\n'; 46 }
task1.cpp源代码:
1 #include "T.h" 2 #include <iostream> 3 4 void test_T(); 5 6 int main() { 7 std::cout << "test Class T: \n"; 8 test_T(); 9 10 std::cout << "\ntest friend func: \n"; 11 func(); 12 } 13 14 void test_T() { 15 using std::cout; 16 using std::endl; 17 18 cout << "T info: " << T::doc << endl; 19 cout << "T objects'max count: " << T::max_cnt << endl; 20 cout << "T objects'current count: " << T::get_cnt() << endl << endl; 21 22 T t1; 23 cout << "t1 = "; t1.display(); cout << endl; 24 25 T t2(3, 4); 26 cout << "t2 = "; t2.display(); cout << endl; 27 28 T t3(t2); 29 t3.adjust(2); 30 cout << "t3 = "; t3.display(); cout << endl; 31 32 T t4(std::move(t2)); 33 cout << "t4 = "; t4.display(); cout << endl; 34 35 cout << "test: T objects'current count: " << T::get_cnt() << endl; 36 }
运行测试截图:

回答问题:
问题1:Yes
问题2:
普通构造函数:功能:创建新对象并初始化数据成员; 创建新对象时
复制构造函数:功能:用已有对象创建新对象; 对象拷贝时
移动构造函数:功能:转移资源所有权而不复制; 使用右值引用时
析构函数:功能:清理对象资源,减少对象计数; 对象生命周期结束时自动调用
问题3:能
2、实验任务2:
Complex.h源代码:
1 #pragma once 2 #include <string> 3 4 class Complex { 5 public: 6 static const std::string doc; 7 8 Complex(double real = 0.0, double imag = 0.0); 9 Complex(const Complex &other); 10 11 double get_real() const; 12 double get_imag() const; 13 void add(const Complex &other); 14 15 friend void output(const Complex &c); 16 friend double abs(const Complex &c); 17 friend Complex add(const Complex &c1, const Complex &c2); 18 friend bool is_equal(const Complex &c1, const Complex &c2); 19 friend bool is_not_equal(const Complex &c1, const Complex &c2); 20 21 private: 22 double real; 23 double imag; 24 };
Complex.cpp源代码:
1 #include "Complex.h" 2 #include <iostream> 3 #include <cmath> 4 5 const std::string Complex::doc = "a simplified Complex class"; 6 7 Complex::Complex(double real, double imag) : real(real), imag(imag) {} 8 Complex::Complex(const Complex &other) : real(other.real), imag(other.imag) {} 9 10 double Complex::get_real() const { return real; } 11 double Complex::get_imag() const { return imag; } 12 void Complex::add(const Complex &other) { 13 real += other.real; 14 imag += other.imag; 15 } 16 17 void output(const Complex &c) { 18 if (c.imag >= 0) { 19 std::cout << c.real << " + " << c.imag << "i"; 20 } else { 21 std::cout << c.real << " - " << -c.imag << "i"; 22 } 23 } 24 25 double abs(const Complex &c) { 26 return std::sqrt(c.real * c.real + c.imag * c.imag); 27 } 28 29 Complex add(const Complex &c1, const Complex &c2) { 30 return Complex(c1.real + c2.real, c1.imag + c2.imag); 31 } 32 33 bool is_equal(const Complex &c1, const Complex &c2) { 34 return c1.real == c2.real && c1.imag == c2.imag; 35 } 36 37 bool is_not_equal(const Complex &c1, const Complex &c2) { 38 return !is_equal(c1, c2); 39 }
task2.cpp
1 #include "Complex.h" 2 #include <iostream> 3 #include <iomanip> 4 #include <complex> 5 6 void test_Complex(); 7 void test_std_complex(); 8 9 int main() { 10 std::cout << "*******测试1:自定义类Complex*******\n"; 11 test_Complex(); 12 13 std::cout << "\n*******测试2:标准库模板类complex*******\n"; 14 test_std_complex(); 15 } 16 17 void test_Complex() { 18 using namespace std; 19 cout << "类成员测试:\n"; 20 cout << Complex::doc << "\n\n"; 21 22 cout << "Complex对象测试:\n"; 23 Complex c1; 24 Complex c2(3, -4); 25 Complex c3(c2); 26 Complex c4 = c2; 27 const Complex c5(3.5); 28 29 cout << "c1 = "; output(c1); cout << "\n"; 30 cout << "c2 = "; output(c2); cout << "\n"; 31 cout << "c3 = "; output(c3); cout << "\n"; 32 cout << "c4 = "; output(c4); cout << "\n"; 33 cout << "c5.real = " << c5.get_real() 34 << ", c5.imag = " << c5.get_imag() << "\n\n"; 35 36 cout << "复数运算测试:\n"; 37 cout << "abs(c2) = " << abs(c2) << "\n"; 38 c1.add(c2); 39 cout << "c1 += c2, c1 = "; output(c1); cout << "\n"; 40 cout << boolalpha; 41 cout << "c1 == c2 : " << is_equal(c1, c2) << "\n"; 42 cout << "c1 != c2 : " << is_not_equal(c1, c2) << "\n"; 43 Complex c6 = add(c2, c3); 44 cout << "c4 = c2 + c3, c4 = "; output(c6); cout << "\n"; 45 } 46 47 void test_std_complex() { 48 using namespace std; 49 cout << "std::complex<double>对象测试:\n"; 50 complex<double> c1; 51 complex<double> c2(3, -4); 52 complex<double> c3(c2); 53 complex<double> c4 = c2; 54 const complex<double> c5(3.5); 55 56 cout << "c1 = " << c1 << "\n"; 57 cout << "c2 = " << c2 << "\n"; 58 cout << "c3 = " << c3 << "\n"; 59 cout << "c4 = " << c4 << "\n"; 60 cout << "c5.real = " << c5.real() 61 << ", c5.imag = " << c5.imag() << "\n\n"; 62 63 cout << "复数运算测试:\n"; 64 cout << "abs(c2) = " << abs(c2) << "\n"; 65 c1 += c2; 66 cout << "c1 += c2, c1 = " << c1 << "\n"; 67 cout << boolalpha; 68 cout << "c1 == c2 : " << (c1 == c2) << "\n"; 69 cout << "c1 != c2 : " << (c1 != c2) << "\n"; 70 complex<double> c6 = c2 + c3; 71 cout << "c4 = c2 + c3, c4 = " << c6 << "\n"; 72 }
运行代码截图:

回答问题:
问题1:标准库模板类complex更简洁;函数和运算逻辑关联一致,都是实部加实部、虚部加虚部,取模都是计算模长
问题2:
2-1:是。output需要访问实部和虚部来格式化输出;abs需要实部和虚部计算模长;add需要访问两个复数的实部和虚部来做加法
2-2:否。标准库std::complex的abs是通过公共接口real()和imag()获取实部、虚部后计算的,未将abs设为友元
2-3:当外部函数需要访问当前类的私有成员
问题3:删除复制构造函数
3、实验任务3:
PlayerControl.cpp源代码:
1 #include "PlayerControl.h" 2 #include <iostream> 3 #include <algorithm> 4 #include <cctype> 5 6 int PlayerControl::total_cnt = 0; 7 8 PlayerControl::PlayerControl() {} 9 10 ControlType PlayerControl::parse(const std::string& control_str) { 11 std::string str = control_str; 12 std::transform(str.begin(), str.end(), str.begin(), ::tolower); 13 14 if (str == "play") { 15 total_cnt++; 16 return ControlType::Play; 17 } else if (str == "pause") { 18 total_cnt++; 19 return ControlType::Pause; 20 } else if (str == "next") { 21 total_cnt++; 22 return ControlType::Next; 23 } else if (str == "prev") { 24 total_cnt++; 25 return ControlType::Prev; 26 } else if (str == "stop") { 27 total_cnt++; 28 return ControlType::Stop; 29 } else { 30 return ControlType::Unknown; 31 } 32 } 33 34 void PlayerControl::execute(ControlType cmd) const { 35 switch (cmd) { 36 case ControlType::Play: std::cout << "[play] Playing music...\n"; break; 37 case ControlType::Pause: std::cout << "[Pause] Music paused\n"; break; 38 case ControlType::Next: std::cout << "[Next] Skipping to next track\n"; break; 39 case ControlType::Prev: std::cout << "[Prev] Back to previous track\n"; break; 40 case ControlType::Stop: std::cout << "[Stop] Music stopped\n"; break; 41 default: std::cout << "[Error] unknown control\n"; break; 42 } 43 } 44 45 int PlayerControl::get_cnt() { 46 return total_cnt; 47 }
PlayerControl.h源代码:
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 };
task3.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 }
运行代码截图:

4、实验任务4:
Fraction.h源代码:
1 #pragma once 2 #include <string> 3 4 class Fraction { 5 public: 6 static const std::string doc; 7 8 Fraction(int up = 0, int down = 1); 9 Fraction(const Fraction &other); 10 11 int get_up() const; 12 int get_down() const; 13 Fraction negative() const; 14 15 friend void output(const Fraction &f); 16 friend Fraction add(const Fraction &f1, const Fraction &f2); 17 friend Fraction sub(const Fraction &f1, const Fraction &f2); 18 friend Fraction mul(const Fraction &f1, const Fraction &f2); 19 friend Fraction div(const Fraction &f1, const Fraction &f2); 20 21 private: 22 int up; 23 int down; 24 25 void reduce(); 26 int gcd(int a, int b); 27 };
Fraction.cpp源代码:
1 #include "Fraction.h" 2 #include <iostream> 3 4 const std::string Fraction::doc = "Fraction类 v 0.01版.\n目前仅支持分数对象的构造、输出、加/减/乘/除运算."; 5 6 Fraction::Fraction(int up, int down) : up(up), down(down) { 7 if (down == 0) { 8 std::cerr << "分母不能为0" << std::endl; 9 exit(1); 10 } 11 reduce(); 12 } 13 14 Fraction::Fraction(const Fraction &other) : up(other.up), down(other.down) {} 15 16 int Fraction::get_up() const { return up; } 17 int Fraction::get_down() const { return down; } 18 19 Fraction Fraction::negative() const { 20 return Fraction(-up, down); 21 } 22 23 void Fraction::reduce() { 24 if (down < 0) { 25 up = -up; 26 down = -down; 27 } 28 int g = gcd(std::abs(up), down); 29 if (g != 0) { 30 up /= g; 31 down /= g; 32 } 33 } 34 35 int Fraction::gcd(int a, int b) { 36 return b == 0 ? a : gcd(b, a % b); 37 } 38 39 void output(const Fraction &f) { 40 if (f.down == 1) { 41 std::cout << f.up; 42 } else { 43 std::cout << f.up << "/" << f.down; 44 } 45 } 46 47 Fraction add(const Fraction &f1, const Fraction &f2) { 48 int up = f1.up * f2.down + f2.up * f1.down; 49 int down = f1.down * f2.down; 50 Fraction res(up, down); 51 res.reduce(); 52 return res; 53 } 54 55 Fraction sub(const Fraction &f1, const Fraction &f2) { 56 int up = f1.up * f2.down - f2.up * f1.down; 57 int down = f1.down * f2.down; 58 Fraction res(up, down); 59 res.reduce(); 60 return res; 61 } 62 63 Fraction mul(const Fraction &f1, const Fraction &f2) { 64 int up = f1.up * f2.up; 65 int down = f1.down * f2.down; 66 Fraction res(up, down); 67 res.reduce(); 68 return res; 69 } 70 71 Fraction div(const Fraction &f1, const Fraction &f2) { 72 if (f2.up == 0) { 73 std::cerr << "分母不能为0" << std::endl; 74 exit(1); 75 } 76 int up = f1.up * f2.down; 77 int down = f1.down * f2.up; 78 Fraction res(up, down); 79 res.reduce(); 80 return res; 81 }
task4.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 }
运行代码截图:

回答问题:选择友元函数方案
理由:优点:可直接访问Fraction类的私有成员,无需通过公共接口间接获取,简化分数运算的实现逻辑;缺点:一定程度上破坏了类的分装性
浙公网安备 33010602011771号