实验3 类和对象_基础编程2

实验任务一

源码

 1 #pragma once
 2 
 3 #include<iostream>
 4 #include<string>
 5 
 6 using std::string;
 7 using std::cout;
 8 
 9 //按钮类
10 class Button {
11 public:
12     Button(const string& text);
13     string get_label()const;
14     void click();
15 
16 private:
17     string label;
18 };
19 
20 Button::Button(const string &text):label{text}{}
21 
22 inline string Button::get_label() const {
23     return label;
24 }
25 
26 void Button::click(){
27     cout << "Button" << label << "clicked\n";
28 }
Button.hpp
 1 #pragma once
 2 #include"button.hpp"
 3 #include<vector>
 4 #include<iostream>
 5 
 6 using std::vector;
 7 using std::cout;
 8 using std::endl;
 9 
10 class window {
11 public:
12     window(const string& win_title);
13     void display()const;
14     void close();
15     void add_button(const string& label);
16 private:
17     string title;
18     vector<Button>buttons;
19 };
20 
21 window::window(const string& win_title) :title{ win_title } {
22     buttons.push_back(Button(" close "));
23 }
24 
25 inline void window::display()const {
26     string s(40, '*');
27 
28     cout << s << endl;
29     cout << "window title:" << title << endl;
30     cout << "It has " << buttons.size() << " buttons: " << endl;
31     for (const auto& i : buttons) {
32         cout << i.get_label() << " button " << endl;
33     }
34     cout << s << endl;
35 }
36 
37 void window::close() {
38     cout << "close window '" << title << "'" << endl;
39     buttons.at(0).click();
40 }
41 
42 void window::add_button(const string &label) {
43     buttons.push_back(Button(label));
44 }
Window.hpp
 1 #include "window.hpp"
 2 #include<iostream>
 3 
 4 using std::cout;
 5 using std::cin;
 6 
 7 void test() {
 8     window w1("new window");
 9     w1.add_button("maximize");
10     w1.display();
11     w1.close();
12 }
13 
14 int main() {
15     cout << "用组合类模拟简单GUI:\n";
16     test();
17 }
task1.cpp

运行结果

问题1:这个模拟简单GUI的示例代码中,自定义了几个类?使用到了标准库的哪几个类?, 哪些类和类之间存在组合关系?

答:定义了Button和Window两个类;使用到标准库中的string,vector;sting定义了Button中label且在Window中有输出,vector定义了Window中的Buttons,是一个string的vector。

问题2:在自定义类Button和Window中,有些成员函数定义时加了const, 有些设置成了 inline。如果你是类的设计者,目前那些没有加const或没有设置成inline的,适合添加const, 适合设置成inline吗?你的思考依据是?

答:click()和close()都没必要加const,因为其没有参数传入;它们也没必要加inline,因为只在开头和结尾使用一次。

  而add_button不能添加const,如果需要频繁的添加button的话可以添加inline

问题3:类Window的定义中,有这样一行代码:string s(40,'*'),其功能是?

答:使用string构造一个字符串,第一个参数是字符串长度int,第二个参数是每个位置应填充的字符;代码将创造含四十个连续*的字符串

 

 

 

实验任务二

源码

 1 #include<iostream>
 2 #include<vector>
 3 
 4 using namespace std;
 5 
 6 void output1(const vector<int>& v) {
 7     for (auto& i : v)
 8         cout << i << ",";
 9     cout << "\b \n";
10 }
11 
12 void output2(const vector<vector<int>>v) {
13     for (auto& i : v)
14     {
15         for (auto& j : i)
16             cout << j << ",";
17         cout << "\b \n";
18     }
19 }
20 
21 void test1() {
22     vector<int>v1(5, 42);
23     const vector<int>v2(v1);
24 
25     v1.at(0) = -999;
26     cout << "v1:"; output1(v1);
27     cout << "v2: "; output1(v2);
28     cout << "v1.at(0) = " << v1.at(0) << endl;
29     cout << "v2.at(0) = " << v2.at(0) << endl;
30 }
31 
32 void test2() {
33     vector<vector<int>>v1{ {1,2,3},{4,5,6,7} };
34     const vector<vector<int>>v2(v1);
35 
36     v1.at(0).push_back(-999);
37     cout << "v1: \n"; output2(v1);
38     cout << "v2: \n"; output2(v2);
39 
40     vector<int>t1 = v1.at(0);
41     cout << t1.at(t1.size() - 1) << endl;
42 
43     const vector<int>t2 = v2.at(0);
44     cout << t2.at(t2.size() - 1) << endl;
45 }
46 
47 int main() {
48     cout << "测试1:\n";
49     test1();
50     cout << "\n测试2:\n";
51     test2();
52 }
task2.cpp

运行测试截图

问题1:测试1模块中,这三行代码的功能分别是?

答:vector<int>v1(5, 42);创造名为v1的一维向量,用五个42填充

  const vector<int>v2(v1);创造一个名为v2的一维向量,用v2初始化它,有const修饰不可修改

  v1.at(0) = -999;用at成员函数访问v1的第一个元素并将它改为-999

问题2:测试2模块中,这三行代码的功能分别是?

答:vector<vector<int>>v1{ {1,2,3},{4,5,6,7} };创造一个名为v1的二维向量,它包含两个一维向量,分别是{1,2,3}和{4,5,6,7}

  const vector<vector<int>>v2(v1);创造一个名为v2的二维向量,用v1初始化它,用const修饰不可修改

  v1.at(0).push_back(-999);用at成员函数访问v1的第一个一维向量,并向末尾添加-999

问题3:测试2模块中,这四行代码的功能分别是?

答:vector<int>t1 = v1.at(0);用 at 成员函数访问 v1 中的第一个一维向量,并将其赋值给名为 t1 的一维向量

  cout << t1.at(t1.size() - 1) << endl;用 at 成员函数访问 t1 中最后一个元素,并输出它的值

  const vector<int>t2 = v2.at(0);用 at 成员函数访问 v2中的第一个一维向量,并将其赋值给名为 t2 的一维向量

  cout << t2.at(t2.size() - 1) << endl;用 at 成员函数访问 t2中最后一个元素,并输出它的值

 

 

 

实验任务三

源码

 1 #pragma once
 2 
 3 #include<iostream>
 4 #include<cassert>
 5 
 6 using std::cout;
 7 using std::endl;
 8 
 9 class vectorInt {
10 public:
11     vectorInt(int n);
12     vectorInt(int n, int value);
13     vectorInt(const vectorInt& vi);
14     ~vectorInt();
15 
16     int& at(int index);
17     const int& at(int index)const;
18 
19     vectorInt& assign(const vectorInt& v);
20     int get_size() const;
21 
22 private:
23     int size;
24     int* ptr;
25 };
26 
27 vectorInt::vectorInt(int n) :size{ n }, ptr{ new int[size] }{}
28 
29 vectorInt::vectorInt(int n, int value) :size{ n }, ptr{ new int[size] } {
30     for (auto i = 0; i < size; ++i)
31         ptr[i] = value;
32 }
33 
34 vectorInt::vectorInt(const vectorInt& vi) :size{ vi.size }, ptr{ new int[size] } {
35     for (auto i = 0; i < size; ++i)
36         ptr[i] = vi.ptr[i];
37 }
38 
39 vectorInt::~vectorInt() {
40     delete[]ptr;
41 }
42 
43 const int& vectorInt::at(int index)const {
44     assert(index >= 0 && index < size);
45 
46     return ptr[index];
47 }
48 
49 int& vectorInt::at(int index) {
50     assert(index >= 0 && index < size);
51 
52     return ptr[index];
53 }
54 
55 vectorInt& vectorInt::assign(const vectorInt& v) {
56     delete[] ptr; //把对象原来的东西删掉
57 
58     size = v.size;
59     ptr = new int[size];
60     
61     for (int i = 0; i < size; ++i)
62         ptr[i] = v.ptr[i];
63 
64     return *this;
65 }
66 
67 int vectorInt::get_size() const {
68     return size;
69 }
vectorInt.hpp
 1 #include"vectorInt.hpp"
 2 #include<iostream>
 3 
 4 using std::cin;
 5 using std::cout;
 6 
 7 void output(const vectorInt& vi) {
 8     for (auto i = 0; i < vi.get_size(); ++i)
 9         cout << vi.at(i) << ",";
10     cout << "\b \n";
11 }
12 
13 void test1() {
14     int n;
15     cout << "Enter n:";
16     cin >> n;
17 
18     vectorInt x1(n);
19     for (auto i = 0; i < n; ++i)
20         x1.at(i) = i * i;
21     cout << "x1: "; output(x1);
22 
23     vectorInt x2(n, 42);
24     vectorInt x3(x2);
25     x2.at(0) = -999;
26     cout << "x2: "; output(x2);
27     cout << "x3: "; output(x3);
28 }
29 
30 void test2() {
31     const vectorInt x(5, 42);
32     vectorInt y(10, 0);
33 
34     cout << "y: "; output(y);
35     y.assign(x);
36     cout << "y: "; output(y);
37 
38     cout << "x.at(0) = " << x.at(0) << endl;
39     cout << "y.at(0) = " << y.at(0) << endl;
40 }
41 
42 int main() {
43     cout << "测试1: \n";
44     test1();
45 
46     cout << "\n测试2: \n";
47     test2();
48 }
task3.cpp

运行测试截图

 问题1:vectorInt类中,复制构造函数(line14)的实现,是深复制还是浅复制?

答:深复制,因为释放了原有资源并且分配了新内存

问题2:vectorInt类中,这两个at()接口,如果返回值类型改成int而非int&(相应地,实现部分也 同步修改),测试代码还能正确运行吗?如果把line18返回值类型前面的const掉,针对这个测试 代码,是否有潜在安全隐患?尝试分析说明。

答:(1)不能。

  (2)如果去掉第一个const(即返回类型变为int&),那么返回的引用将不再是对常量的引用,调用者可以通过这个引用来修改整数值。这可能会破坏类的封装性,特别是如果这个函数返回的是类的内部数据结构的直接引用的话。如果去掉第二个const(即函数声明变为int& at(int index)),那么该函数将不再是一个常量成员函数,它将能够修改调用它的对象的状态。这可能会导致在不应该修改对象状态的情况下意外地修改了对象,从而引入难以追踪的错误。

问题3:vectorInt类中,assign()接口,返回值类型可以改成vectorInt吗?你的结论,及,原因分析。

答:不可以?运行结果没有出错,但是返回对象会带来不必要的复制,而且如果错误返回对象的引用会导致未定义行为

 

 

 

实验任务四

源码

 1 #pragma once
 2 
 3 #include<iostream>
 4 #include<cassert>
 5 #include<cstring>
 6 
 7 using std::cout;
 8 using std::endl;
 9 
10 // 类Matrix的声明
11 class Matrix {
12 public:
13     Matrix(int n, int m);    // 构造函数,构造一个n*m的矩阵, 初始值为value
14     Matrix(int n);            // 构造函数,构造一个n*n的矩阵, 初始值为value
15     Matrix(const Matrix& x);// 复制构造函数, 使用已有的矩阵X构造
16     ~Matrix();
17 
18     void set(const double* pvalue);// 用pvalue指向的连续内存块数据按行为矩阵赋值
19     void clear(); //把矩阵对象的值置零
20     const double& at(int i, int j) const; // 返回矩阵对象索引(i,j)的元素const引用
21     double& at(int i, int j); // 返回矩阵对象索引(i,j)的元素引用
22     int get_lines() const; // 返回矩阵对象行数
23     int get_cols() const; // 返回矩阵对象列数
24     void display() const; // 按行显示矩阵对象元素值
25 
26 private:
27     int lines;
28     int cols;
29     double* ptr;
30 };
31 
32 //构造函数
33 Matrix::Matrix(int n, int m) :lines{ n }, cols{ m }, ptr{ new double[lines*cols]} {}
34 Matrix::Matrix(int n) :Matrix(n, n) {};
35 Matrix::Matrix(const Matrix&x) :lines { x.lines }, cols{ x.cols}, ptr{ new double[x.lines * x.cols] } {
36     std::memcpy(ptr, x.ptr, sizeof(double) * x.lines * x.cols);//怎么方便成这样 :)
37 }
38 
39 //析构函数
40 Matrix::~Matrix() {
41     delete[]ptr;
42 }
43 
44 //按行赋值
45 void Matrix::set(const double* pvalue) {
46     std::memcpy(ptr, pvalue, sizeof(double) * lines * cols);
47 }
48 
49 //置零
50 void Matrix::clear() {
51     std::memset(ptr, 0, sizeof(double) * lines * cols);
52 }
53 
54 //返回(i,j)位置元素的const引用
55 const double& Matrix::at(int i, int j)const {
56     assert(i >= 0 && j >= 0 && i < lines && j < cols);
57     return ptr[i * cols + j];//这里好容易错!
58 }
59 
60 //返回(i,j)位置元素的引用
61 double& Matrix::at(int i, int j) {
62     assert(i >= 0 && j >= 0 && i < lines && j < cols);
63     return ptr[i * cols + j];
64 }
65 
66 //返回行数
67 int Matrix::get_lines()const {
68     return lines;
69 }
70 
71 //返回列数
72 int Matrix::get_cols()const {
73     return cols;
74 }
75 
76 //按行显示矩阵的元素值
77 void Matrix::display()const {
78     for (auto i = 0; i < lines; ++i) {
79         for (auto j = 0; j < cols; ++j) {
80             cout << at(i, j) << " ";
81         }
82         cout << endl;
83     }
84 }
Matrix.hpp
 1 #include "matrix.hpp"
 2 #include <iostream>
 3 #include <cassert>
 4 
 5 using std::cin;
 6 using std::cout;
 7 using std::endl;
 8 
 9 const int N = 1000;
10 
11 
12 // 输出矩阵对象索引为index所在行的所有元素
13 void output(const Matrix& m, int index) {
14     assert(index >= 0 && index < m.get_lines());
15     for (auto j = 0; j < m.get_cols(); ++j)
16         cout << m.at(index, j) << ", ";
17     cout << "\b\b \n";
18 }
19 
20 
21 void test1() {
22     double x[1000] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
23     int n, m;
24     cout << "Enter n and m: ";
25     cin >> n >> m;
26     Matrix m1(n, m); // 创建矩阵对象m1, 大小n×m
27     m1.set(x); // 用一维数组x的值按行为矩阵m1赋值
28     Matrix m2(m, n); // 创建矩阵对象m1, 大小m×n
29     m2.set(x); // 用一维数组x的值按行为矩阵m1赋值
30     Matrix m3(2); // 创建一个2×2矩阵对象
31     m3.set(x); // 用一维数组x的值按行为矩阵m4赋值
32     cout << "矩阵对象m1: \n"; m1.display(); cout << endl;
33     cout << "矩阵对象m2: \n"; m2.display(); cout << endl;
34     cout << "矩阵对象m3: \n"; m3.display(); cout << endl;
35 }
36 
37 
38 void test2() {
39     Matrix m1(2, 3);
40     m1.clear();
41     const Matrix m2(m1);
42     m1.at(0, 0) = -999;
43     cout << "m1.at(0, 0) = " << m1.at(0, 0) << endl;
44     cout << "m2.at(0, 0) = " << m2.at(0, 0) << endl;
45     cout << "矩阵对象m1第0行: "; output(m1, 0);
46     cout << "矩阵对象m2第0行: "; output(m2, 0);
47 }
48 
49 
50 int main() {
51     cout << "测试1: \n";
52     test1();
53     cout << "测试2: \n";
54     test2();
55 }
task4.cpp

运行测试截图

 

 

 

实验任务五

源码

 1 #pragma once
 2 
 3 #include<iostream>
 4 #include<string>
 5 
 6 using std::string;
 7 using std::endl;
 8 using std::cout;
 9 using std::cin;
10 
11 class User {
12 private:
13     string user;
14     string id;
15     string email;
16     string password;
17 
18 public:
19     //user必须输入
20     User(const string &user,const string &id="",const string&email="")
21         :user(user), id(id), email(email), password("123456") {}
22     //User(const string& user)
23     //    :user(user), id(""), email(""), password("") {}
24 
25     void set_email() {
26         email.clear();
27         cout << "Enter email address: ";
28         std::getline(cin, email);//能读取空格
29         while (email.find('@') == std::string::npos) {
30             email.clear();
31             cout << "illegal email.Please re-enter email:";
32             std::getline(cin, email);
33         }
34         cout << "email is set successfully..."<<endl;
35     }
36 
37     void change_password() {
38         //验证密码
39         cout << "Enter old password: ";
40         string old_pass;
41         std::getline(cin, old_pass);
42         int cnt = 0;//记录输入错误次数,三次锁定
43         while (old_pass != password)
44         {
45             cnt++;
46             if (cnt == 3) {
47                 cout << "password input error. Please try after a while." << endl;
48                 return;
49             }
50             old_pass.clear();
51             cout << "password input error. Please re-enter again:";//老师你again打错了:(
52             std::getline(cin,old_pass);
53         }
54         password.clear();
55         cout << "Enter new password: ";
56         std::getline(cin, password);
57         cout << "new password is set successfully..." << endl;
58     }
59 
60     void display()const {
61         cout << "name:  " << user << endl;
62         string password_private(password.size(), '*');
63         cout << "pass:  " << password_private << endl;
64         cout << "email:  " << email << endl;
65         cout << endl;
66     }
67 };
User.hpp
 1 #include "user.hpp"
 2 #include <iostream>
 3 #include <vector>
 4 #include <string>
 5 using std::cin;
 6 using std::cout;
 7 using std::endl;
 8 using std::vector;
 9 using std::string;
10 
11 
12 void test() {
13     vector<User> user_lst;
14     User u1("Alice", "2024113", "Alice@hotmail.com");
15     user_lst.push_back(u1);
16     cout << endl;
17     User u2("Bob");
18     u2.set_email();
19     u2.change_password();
20     user_lst.push_back(u2);
21     cout << endl;
22     User u3("Hellen");
23     u3.set_email();
24     u3.change_password();
25     user_lst.push_back(u3);
26     cout << endl;
27     cout << "There are " << user_lst.size() << " users. they are: " << endl;
28     for (auto& i : user_lst) {
29         i.display();
30         cout << endl;
31     }
32 }
33 
34 int main() {
35     test();
36 }
task5.cpp

运行测试截图

 

 

 

实验任务六

源码

 1 #pragma once 
 2 #include <iostream>  
 3 #include <cstdlib>  
 4 using namespace std;
 5 
 6 class Date {
 7 private:
 8     int year;
 9     int month;
10     int day;
11     int totalDays;
12 public:
13     Date(int year, int month, int day);
14     int getYear() const { return year; }
15     int getMonth() const { return month; }
16     int getDay() const { return day; }
17     int getMaxDay() const;
18     bool isLeapYear() const {
19         return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
20     }
21     void show() const;
22     int distance(const Date& date) const {
23         return totalDays - date.totalDays;
24     }
25 };
26 
27 namespace {
28     const int DAYS_BEFORE_MONTH[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
29 }
30 
31 Date::Date(int year, int month, int day) : year(year), month(month), day(day) {
32     if (day <= 0 || day > getMaxDay()) {
33         cout << "Invalid date: ";
34         show();
35         cout << endl;
36         exit(1);
37     }
38     int years = year - 1;
39     totalDays = years * 365 + years / 4 - years / 100 + years / 400 + DAYS_BEFORE_MONTH[month - 1] + day;
40     if (isLeapYear() && month > 2) totalDays++;
41 }
42 
43 int Date::getMaxDay() const {
44     if (isLeapYear() && month == 2)
45         return 29;
46     else
47         return DAYS_BEFORE_MONTH[month] - DAYS_BEFORE_MONTH[month - 1];
48 }
49 
50 void Date::show() const {
51     cout << getYear() << "-" << getMonth() << "-" << getDay();
52 }
date.hpp
 1 #pragma once  
 2 #include "date.hpp"  
 3 #include <string>  
 4 #include <cmath>  
 5 #include <iostream>  
 6 using namespace std;
 7 
 8 class SavingsAccount {
 9 private:
10     string id;
11     double balance;
12     double rate;
13     Date lastDate;
14     double accumulation;
15     static double total;
16     void record(const Date& date, double amount, const string& desc);
17     void error(const string& msg) const;
18     double accumulate(const Date& date) const {
19         return accumulation + balance * date.distance(lastDate);
20     }
21 public:
22     SavingsAccount(const Date& date, const string& id, double rate);
23     const string& getId() const { return id; }
24     double getBalance() const { return balance; }
25     double getRate() const { return rate; }
26     static double getTotal() { return total; }
27     void deposit(const Date& date, double amount, const string& desc);
28     void withdraw(const Date& date, double amount, const string& desc);
29     void settle(const Date& date);
30     void show() const;
31 };
32 
33 double SavingsAccount::total = 0;
34 
35 SavingsAccount::SavingsAccount(const Date& date, const string& id, double rate) :
36     id(id), balance(0), rate(rate), lastDate(date), accumulation(0) {
37     date.show();
38     cout << "\t#" << id << " created" << endl;
39 }
40 
41 void SavingsAccount::record(const Date& date, double amount, const string& desc) {
42     accumulation = accumulate(date);
43     lastDate = date;
44     amount = floor(amount * 100 + 0.5) / 100;
45     balance += amount;
46     total += amount;
47     date.show();
48     cout << "\t#" << id << "\t" << amount << "\t" << balance << "\t" << desc << endl;
49 }
50 
51 void SavingsAccount::error(const string& msg) const {
52     cout << "Error(#" << id << "):" << msg << endl;
53 }
54 
55 void SavingsAccount::deposit(const Date& date, double amount, const string& desc) {
56     record(date, amount, desc);
57 }
58 
59 void SavingsAccount::withdraw(const Date& date, double amount, const string& desc) {
60     if (amount > getBalance())
61         error("not enough money");
62     else
63         record(date, -amount, desc);
64 }
65 
66 void SavingsAccount::settle(const Date& date) {
67     double interest = accumulate(date) * rate / date.distance(Date(date.getYear() - 1, 1, 1));
68     if (interest != 0) record(date, interest, "interest");
69     accumulation = 0;
70 }
71 
72 void SavingsAccount::show() const {
73     cout << id << "\tBalance: " << balance;
74 }
account.cpp
 1 #include "account.hpp"  
 2 #include <iostream>  
 3 using namespace std;
 4 
 5 int main() {
 6     Date date{ 2008, 11, 1 };
 7     SavingsAccount accounts[] = {
 8         SavingsAccount(date, "03755217", 0.015),
 9         SavingsAccount(date, "02342342", 0.015)
10     };
11     const int n = sizeof(accounts) / sizeof(SavingsAccount);
12     accounts[0].deposit(Date(2008, 11, 5), 5000, "salary");
13     accounts[1].deposit(Date(2008, 11, 25), 10000, "sell stock 0323");
14     accounts[0].deposit(Date(2008, 12, 5), 5500, "salary");
15     accounts[1].withdraw(Date(2008, 12, 20), 4000, "buy a laptop");
16     cout << endl;
17     for (int i = 0; i < n; i++) {
18         accounts[i].settle(Date(2009, 1, 1));
19         accounts[i].show();
20         cout << endl;
21     }
22     cout << "Total: " << SavingsAccount::getTotal() << endl;
23     return 0;
24 }
task6.cpp

运行测试截图

 

posted @ 2024-11-04 21:01  姚润勰  阅读(12)  评论(0编辑  收藏  举报