🧪 實驗報告
一、實驗名稱
實驗2 類和對象_基礎編程2
二、實驗目的
理解類的組合機制(has-a),能熟練用 C++ 定義與使用組合類
理解深複製與淺複製的區別
靈活運用標準庫(array、vector、string、迭代器、算法庫等)解決實際問題
面向具體問題,運用面向對象思維設計類(自定義/標準庫),合理組合並編程解決
三、實驗內容
- 實驗任務1
問題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 和 )實現 RAII 和高效邏輯封裝的重要性,體現了零成本抽象的設計哲學,即在保證安全性的同時不犧牲性能。