🧪 實驗報告

一、實驗名稱

實驗2 類和對象_基礎編程2

二、實驗目的

理解類的組合機制(has-a),能熟練用 C++ 定義與使用組合類
理解深複製與淺複製的區別
靈活運用標準庫(array、vector、string、迭代器、算法庫等)解決實際問題
面向具體問題,運用面向對象思維設計類(自定義/標準庫),合理組合並編程解決

三、實驗內容

  1. 實驗任務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開始的數組中
第三個同上

  1. 實驗任務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';
  }
}


  1. 實驗任務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 和高效邏輯封裝的重要性,體現了零成本抽象的設計哲學,即在保證安全性的同時不犧牲性能。