实验3

任务一

image

 

问题1:这个范例中,Window和Button是组合关系吗?

答::::是的。Window 类包含了一个 std::vector<Button> 成员变量 buttons。这意味着一个 Window 对象拥有(owns)多个 Button 对象,并且这些 Button 对象的生命周期由 Window 对象管理。当 Window 对象被销毁时,其内部的所有 Button 对象也会随之被销毁。

 

问题2: bool has_button(const std::string &label) const; 被设计为私有。 思考并回答:

答:::: (1)若将其改为公有接口,有何优点或风险?

      优点:外部用户可主动查询某个按钮是否存在,增强类的灵活性

      风险:暴露了内部实现细节

    (2)设计类时,如何判断一个成员函数应为 public 还是 private?(可从“用户是否需要”、“是否仅为内部实现 细节”、“是否易破坏对象状态”等角度分析。)

     若该函数是面向用户的必要操作(如 add_buttonclick_button),应为 public。若仅为内部辅助逻辑(如检查重复、排序等),且用户无需也不应直接调用,则应为 private。若暴露后易破坏对象状态一致性(如允许外部直接修改内部容器),则必须隐藏。

 

问题3: Button 的接口 两种接口设计在性能和安全性方面的差异并精炼陈述。 接口1: const std::string& get_label() const;返回 const std::string& get_label() const; 接口2: const std::string get_label() const;

答::::接口1(const std::string&):性能:避免拷贝,直接返回引用,高效。安全性:返回 const 引用,禁止外部修改原始数据,安全     

接口2(const std::string):性能:每次调用都构造并返回一个新 string 对象,有拷贝开销。安全性:同样不可修改原始数据,但效率低。

问题4:把代码中所有 const std::string& 。对比以下 xx.push_back(Button(xxx)) 改成 xx.emplace_back(xxx) ,观察程序是否正常运 行;查阅资料,回答两种写法的差别

答:::可行,程序正常运行。差别:push_back(Button(xxx)):先构造临时 Button 对象,再将其拷贝或移动进容器。emplace_back(xxx):直接在容器内存中原位构造 Button 对象,避免临时对象和拷贝/移动开销。优势:emplace_back 更高效,尤其对复杂对象。

任务二

image

 

问题1:test1() 中两行代码完成什么构造?v1、v2 各有多少个 42?

std::vector<int> v1(5, 42);:调用 填充构造函数,创建含 5 个 42 的 v1const std::vector<int> v2(v1);:调用 拷贝构造函数,v2 也含 5 个 42

问题2:test2() 中执行后,v1.size()v2.size()v1[0].size() 分别是多少

v1.size() = 2(外层 vector 有 2 行)v2.size() = 2(拷贝后相同)v1[0].size() = 3(第一行 {1,2,3}

问题3:v1.at(0) = -1;v1[0] = -1; 效果是否相同?区别?

效果相同(都能赋值)。

区别:at() 带边界检查,越界抛出 std::out_of_range 异常。operator[] 无检查,越界行为未定义(可能崩溃或数据损坏)。 调试/安全场景优先用 at()

问题4:执行 v1.at(0).push_back(-1); 后:

(1)能否用以下代码输出 -1?为什么?

不能。因为 r 是 vector<int> 的拷贝(值语义),r.back() 输出的是原 v1[0] 修改前的最后一个元素(7),而非 -1

正确做法:用 const auto& r = v1.at(0); 获取引用。

(2)用 const& 接收返回值的优势与限制?

优势:避免拷贝,节省内存和时间。

限制:不能通过该引用修改对象(因是 const)。

问题5:推断 vector 的复制行为及 at() 重载必要性

(1)vector 复制是深复制:修改 v1 不影响 v2,说明内部数据独立。
(2)at() 必须提供 const 重载:

非 const 对象调用 at() 返回 T&(可修改)。const 对象调用 at() 返回 const T&(只读)。若无 const 重载,const 对象无法调用 at(),违反 const 正确性。

任务三

问题1:assign 版本2的安全隐患?
缺陷:

  1. 未处理自赋值(this == &vi):若 vi 就是当前对象,delete[] ptr 后 vi.ptr 已失效,后续读取 vi.ptr[i] 是未定义行为。
  2. 异常不安全:若 new int[n] 抛异常(如内存不足),ptr 已被删除,对象处于无效状态(资源泄漏 + 悬空指针)。

问题2:关于 static_castconst_cast 的作用

(1)static_cast<const vectorInt*>(this)

作用:将 this(类型 vectorInt*)转为 const vectorInt*

目的:在非 const 成员函数中,复用 const 版本的 at() 实现,避免代码重复。

转换后类型:const vectorInt*

(2)const_cast<int&>(...)

作用:去除 const 限定,将 const int& 转为 int&

目的:使非 const at() 能返回可修改的引用。

转换前类型:const int&;后:int&

问题3:begin() 重载选择与迭代器理解

(1)重载选择:vectorInt v1(5); → v1.begin() 调用 非 const 版本(返回 int*)。const vectorInt v2(5); → v2.begin() 调用 const 版本(返回 const int*)。

原则:根据对象是否 const 决定调用哪个重载。

(2)拓展思考:

迭代器本质是泛化的指针。vectorInt 直接返回原始指针,说明简单容器可用指针作为迭代器,体现“零成本抽象”——高性能且接口统一。

问题4:使用 <algorithm> 改写是否可行?功能解释

可行。三行更新代码功能:std::fill_n(ptr, n, value);:将 ptr 开始的 n 个元素赋值为 valuestd::copy_n(vi.ptr, vi.n, ptr);:从 vi.ptr 复制 vi.n 个元素到 ptr

同上,用于 assign 中的临时缓冲区填充。
使用标准算法更简洁、安全、高效。

任务四

matrix.cpp

 

 1 #include "matrix.hpp"
 2 #include <iostream>
 3 #include <cstdlib>  // for std::exit
 4 #include <algorithm> // for std::fill_n
 5 
 6 // 辅助函数:检查索引是否越界
 7 void check_bounds(int i, int j, int rows, int cols) {
 8     if (i < 0 || i >= rows || j < 0 || j >= cols) {
 9         std::cerr << "IndexError: index out of range\n";
10         std::exit(1);
11     }
12 }
13 
14 // 构造 rows × cols 矩阵
15 Matrix::Matrix(int rows_, int cols_, double value)
16     : n_rows(rows_), n_cols(cols_), ptr(new double[rows_ * cols_]) {
17     std::fill_n(ptr, rows_ * cols_, value);
18 }
19 
20 // 构造方阵 rows × rows
21 Matrix::Matrix(int rows_, double value)
22     : Matrix(rows_, rows_, value) {}  // 委托构造
23 
24 // 深拷贝构造函数
25 Matrix::Matrix(const Matrix& x)
26     : n_rows(x.n_rows), n_cols(x.n_cols), ptr(new double[n_rows * n_cols]) {
27     std::copy_n(x.ptr, n_rows * n_cols, ptr);
28 }
29 
30 // 析构函数
31 Matrix::~Matrix() {
32     delete[] ptr;
33 }
34 
35 // 按行设置数据
36 void Matrix::set(const double* pvalue, int size) {
37     if (size != n_rows * n_cols) {
38         std::cerr << "SizeError: size must be rows * cols\n";
39         std::exit(1);
40     }
41     std::copy_n(pvalue, size, ptr);
42 }
43 
44 // 清零
45 void Matrix::clear() {
46     std::fill_n(ptr, n_rows * n_cols, 0.0);
47 }
48 
49 // const 版 at
50 const double& Matrix::at(int i, int j) const {
51     check_bounds(i, j, n_rows, n_cols);
52     return ptr[i * n_cols + j];
53 }
54 
55 // 非 const 版 at
56 double& Matrix::at(int i, int j) {
57     check_bounds(i, j, n_rows, n_cols);
58     return ptr[i * n_cols + j];
59 }
60 
61 // 获取行数
62 int Matrix::rows() const {
63     return n_rows;
64 }
65 
66 // 获取列数
67 int Matrix::cols() const {
68     return n_cols;
69 }
70 
71 // 按行打印矩阵
72 void Matrix::print() const {
73     for (int i = 0; i < n_rows; ++i) {
74         for (int j = 0; j < n_cols; ++j) {
75             std::cout << at(i, j);
76             if (j < n_cols - 1) std::cout << " ";
77         }
78         std::cout << '\n';
79     }
80 }

 

结果

image

 任务五

 

#pragma once
#include "contact.hpp"
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>

class ContactBook {
public:
    void add(const std::string& name, const std::string& phone) {
        if (index(name) != -1) {
            std::cout << name << " already exists. fail to add!\n";
            return;
        }
        contacts.emplace_back(name, phone);
        sort();
        std::cout << name << " add successfully.\n";
    }

    void display() const {
        std::cout << "There are " << contacts.size() << " contacts.\n";
        for (const auto& c : contacts) {
            std::cout << c.get_name() << "," << c.get_phone() << "\n";
        }
    }

    void find(const std::string& name) const {
        int idx = index(name);
        if (idx == -1) {
            std::cout << name << " not found!\n";
        } else {
            std::cout << contacts[idx].get_name() << "," 
                      << contacts[idx].get_phone() << "\n";
        }
    }

    void remove(const std::string& name) {
        int idx = index(name);
        if (idx == -1) {
            std::cout << name << " not found, fail to remove!\n";
        } else {
            contacts.erase(contacts.begin() + idx);
            std::cout << name << " remove successfully.\n";
        }
    }

private:
    std::vector<Contact> contacts;

    // 待补足1:返回联系人索引,不存在返回-1
    int index(const std::string& name) const {
        for (size_t i = 0; i < contacts.size(); ++i) {
            if (contacts[i].get_name() == name) {
                return static_cast<int>(i);
            }
        }
        return -1;
    }

    // 待补足2:按姓名字典序升序排序
    void sort() {
        std::sort(contacts.begin(), contacts.end(),
            [](const Contact& a, const Contact& b) {
                return a.get_name() < b.get_name();
            });
    }
};

 

 

 

 

#include "matrix.hpp"#include <iostream>#include <cstdlib>  // for std::exit#include <algorithm> // for std::fill_n
// 辅助函数:检查索引是否越界void check_bounds(int i, int j, int rows, int cols) {    if (i < 0 || i >= rows || j < 0 || j >= cols) {        std::cerr << "IndexError: index out of range\n";        std::exit(1);    }}
// 构造 rows × cols 矩阵Matrix::Matrix(int rows_, int cols_, double value)    : n_rows(rows_), n_cols(cols_), ptr(new double[rows_ * cols_]) {    std::fill_n(ptr, rows_ * cols_, value);}
// 构造方阵 rows × rowsMatrix::Matrix(int rows_, double value)    : Matrix(rows_, rows_, value) {}  // 委托构造
// 深拷贝构造函数Matrix::Matrix(const Matrix& x)    : n_rows(x.n_rows), n_cols(x.n_cols), ptr(new double[n_rows * n_cols]) {    std::copy_n(x.ptr, n_rows * n_cols, ptr);}
// 析构函数Matrix::~Matrix() {    delete[] ptr;}
// 按行设置数据void Matrix::set(const double* pvalue, int size) {    if (size != n_rows * n_cols) {        std::cerr << "SizeError: size must be rows * cols\n";        std::exit(1);    }    std::copy_n(pvalue, size, ptr);}
// 清零void Matrix::clear() {    std::fill_n(ptr, n_rows * n_cols, 0.0);}
// const 版 atconst double& Matrix::at(int i, int j) const {    check_bounds(i, j, n_rows, n_cols);    return ptr[i * n_cols + j];}
// 非 const 版 atdouble& Matrix::at(int i, int j) {    check_bounds(i, j, n_rows, n_cols);    return ptr[i * n_cols + j];}
// 获取行数int Matrix::rows() const {    return n_rows;}
// 获取列数int Matrix::cols() const {    return n_cols;}
// 按行打印矩阵void Matrix::print() const {    for (int i = 0; i < n_rows; ++i) {        for (int j = 0; j < n_cols; ++j) {            std::cout << at(i, j);            if (j < n_cols - 1) std::cout << " ";        }        std::cout << '\n';    }}
posted @ 2025-11-25 22:57  KXJSLL  阅读(14)  评论(1)    收藏  举报