NUIST_LAB03
🧪 实验报告
一、实验名称
实验2 类和对象_基础编程2
二、实验目的
理解类的组合机制(has-a),能熟练用 C++ 定义与使用组合类
理解深复制与浅复制的区别
灵活运用标准库(array、vector、string、迭代器、算法库等)解决实际问题
面向具体问题,运用面向对象思维设计类(自定义/标准库),合理组合并编程解决
三、实验内容
- 实验任务1
![image]()
问题1:是
问题2:优点:测试比较方便,便于了解对象内部状态
缺点:增加了接口的维护成本,暴露了内部实现细节
根据最小接口(ISP)原则进行设计
如果用户需要就public,是内部细节就private,可能会破坏对象状态就private
问题3:性能:返回引用避免拷贝,更快;安全性上第二个更好,返回引用会面对悬垂问题,如果button先于获取引用的的地方被销毁将会发生未定义行为
问题4:emplace_back使用perfect forwarding和变长参数表就地构造对象,性能更高
2. 实验任务2

问题1:填充构造,拷贝构造;5,5
问题2:2,2,3
问题3:大概率相同;是否会发生越界检查
问题4:能 r是v1[0]的alias 话说这个问题是不是有点奇怪
因为是常量引用,所以是v1[0]的alias,限制是通过r只能进行只读访问
问题5:深
int
const int
是
3. 实验任务3

问题1:如果传入自己,那么第一步把空间释放了vi.ptr[i]会访问到错误区域
用中间量的话new失败了好处理,可以直接加catch throw
这种较底层的数据结构好像也不能用智能指针
问题2:将this由vectorInt转换为const vectorInt, 转换成可以指向const对象的指针,然后就可以调用const版本的at
说到这里我特地查了一下,一般都是实现const版本然后非const版本通过类型转换进行调用,但是很显然我做课设的时候忘记了这一点:(
作用是消const,原const int&,先int&
问题3:非const;const
迭代器封装了指针的行为,让指针变得更加安全,不同类型的迭代器(比如随机访问迭代器和顺序访问迭代器)就像特殊函数,可以安全的作为参数提供给其他函数使用
就像golang中的interface,只要实现了对应的迭代器类型,就可以直接适配所有拥有这个接口的函数,在保证安全性的前提下极大增强了可扩展性
问题4:可以
从ptr开始向后n个填充value
从vi.ptr开始,向后vi.n个元素填充到从ptr开始的数组中
第三个同上
- 实验任务4
#include "matrix.hpp"
void die(const char *msg) {
std::cerr << msg << '\n';
std::exit(-1);
}
Matrix::Matrix(int rows_, int cols_, double value)
: n_rows(rows_), n_cols(cols_), ptr(nullptr) {
if (n_rows <= 0 || n_cols <= 0)
die("ValueError: invalid matrix size");
ptr = new double[n_rows * n_cols];
std::fill(ptr, ptr + n_rows * n_cols, value);
}
Matrix::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(nullptr) {
ptr = new double[n_rows * n_cols];
std::copy(x.ptr, 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)
die("ValueError: size mismatch");
if (!pvalue)
die("ValueError: null data source");
std::copy(pvalue, pvalue + size, ptr);
}
void Matrix::clear() { std::fill(ptr, ptr + n_rows * n_cols, 0); }
const double &Matrix::at(int i, int j) const {
if (i < 0 || i >= n_rows || j < 0 || j >= n_cols)
die("IndexError: index out of range");
return ptr[i * n_cols + j];
}
double &Matrix::at(int i, int j) {
if (i < 0 || i >= n_rows || j < 0 || j >= n_cols)
die("IndexError: index out of range");
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) {
if (n_cols == 0) {
std::cout << '\n';
continue;
}
std::cout << ptr[i * n_cols];
for (int j = 1; j < n_cols; ++j)
std::cout << ' ' << ptr[i * n_cols + j];
std::cout << '\n';
}
}

- 实验任务5
// 待补足1:int index(const std::string &name) const;实现
// 返回联系人在contacts内索引; 如不存在,返回-1
int ContactBook::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 ContactBook::sort();实现
// 按姓名字典序升序排序通讯录
void ContactBook::sort() {
std::sort(contacts.begin(), contacts.end(),
[](const Contact &lhs, const Contact &rhs) {
return lhs.get_name() < rhs.get_name();
});
}

四、实验结论
本次实验验证了 C++ 中面向对象设计和资源管理的关键机制。在任务一中,通过 Window 和 Button 的组合关系,理解了组合(Has-A)的定义及其生命周期依赖性。任务二和任务三通过对 std::vector 和自定义 vectorInt 的观察,深入理解了深复制与浅复制的根本区别,确认了标准库容器采用深复制,并掌握了实现自定义深复制所需的“三/五法则”(包括拷贝构造和异常安全的 assign 实现)。同时,实验验证了 const 成员函数的必要性,以及使用 const_cast 在非 const 版本中复用 const 版本的代码复用技巧。最后,任务四和任务五的应用性实验强化了利用标准库(如 std::vector 和


浙公网安备 33010602011771号