面试题答案
一键面试#include <iostream>
#include <stdexcept>
class Matrix {
private:
int rows;
int cols;
double** data;
public:
// 第一个构造函数:接受行数和列数,初始化一个全零矩阵
Matrix(int r, int c) : rows(r), cols(c) {
try {
data = new double*[rows];
for (int i = 0; i < rows; ++i) {
data[i] = new double[cols](); // 使用值初始化,所有元素初始化为0
}
} catch (const std::bad_alloc& e) {
// 处理内存分配失败的情况,释放已分配的内存
for (int i = 0; i < rows; ++i) {
delete[] data[i];
}
delete[] data;
throw;
}
}
// 第二个构造函数:接受一个现有的二维数组、行数和列数,用给定数组的数据初始化矩阵
Matrix(double** arr, int r, int c) : rows(r), cols(c) {
try {
data = new double*[rows];
for (int i = 0; i < rows; ++i) {
data[i] = new double[cols];
for (int j = 0; j < cols; ++j) {
data[i][j] = arr[i][j];
}
}
} catch (const std::bad_alloc& e) {
// 处理内存分配失败的情况,释放已分配的内存
for (int i = 0; i < rows; ++i) {
delete[] data[i];
}
delete[] data;
throw;
}
}
// 第三个构造函数:接受另一个矩阵对象作为参数,进行深拷贝构造
Matrix(const Matrix& other) : rows(other.rows), cols(other.cols) {
try {
data = new double*[rows];
for (int i = 0; i < rows; ++i) {
data[i] = new double[cols];
for (int j = 0; j < cols; ++j) {
data[i][j] = other.data[i][j];
}
}
} catch (const std::bad_alloc& e) {
// 处理内存分配失败的情况,释放已分配的内存
for (int i = 0; i < rows; ++i) {
delete[] data[i];
}
delete[] data;
throw;
}
}
~Matrix() {
for (int i = 0; i < rows; ++i) {
delete[] data[i];
}
delete[] data;
}
// 打印矩阵内容,方便测试
void print() const {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
std::cout << data[i][j] << " ";
}
std::cout << std::endl;
}
}
};
设计思路及潜在陷阱
-
第一个构造函数:
- 设计思路:根据传入的行数和列数,动态分配二维数组,并使用值初始化将所有元素初始化为0。这样可以确保矩阵初始状态为全零,满足特定需求。
- 潜在陷阱:内存分配可能失败,需要使用
try-catch
块捕获std::bad_alloc
异常,并在捕获异常后释放已分配的内存,以避免内存泄漏。
-
第二个构造函数:
- 设计思路:接受外部传入的二维数组,根据行数和列数动态分配内存,并将外部数组的数据复制到新分配的矩阵中。这使得可以直接使用已有的数据初始化矩阵。
- 潜在陷阱:同样存在内存分配失败的风险,在捕获异常时需要释放已分配的内存。同时,要注意传入的二维数组的正确性,例如其行数和列数是否与传入的参数匹配,这在实际应用中可能需要额外的验证逻辑。
-
第三个构造函数:
- 设计思路:深拷贝构造函数用于创建一个与传入矩阵对象完全相同的新矩阵对象。它首先分配与原矩阵相同大小的内存,然后逐元素复制数据。
- 潜在陷阱:内存分配失败的处理方式与前两个构造函数相同。同时,要确保对原矩阵对象的元素复制是深拷贝,即新矩阵对象的数据独立于原矩阵对象,修改新矩阵不会影响原矩阵,反之亦然。