C++类内调用以本类为参数的非成员函数实现方法
问题背景
需要在C++类成员函数内部,调用定义在同一头文件中、以当前类类型作为入参的非成员函数。常规将非成员函数声明放在类定义前的写法会因为类尚未完成定义,无法作为有效参数类型触发编译错误。
示例待修改代码如下:
#pragma once #include <vector> #include <tuple> enum MatrixType { Identity, Zeros, Ones }; class Matrix { private: int col, row; typedef std::vector<double> Row; std::vector<Row> data; public: Matrix(int columns, int rows): row(rows), col(columns), data(columns, std::vector<double>(rows)) {} Matrix(int columns, int rows, MatrixType matrixType) : row(rows), col(columns), data(columns, std::vector<double>(rows)) { switch (matrixType) { case Identity: this->MakeIdentity(); break; case Zeros: this->Fill(0); break; case Ones: this->Fill(1); break; default: break; } } Row& operator[](int i) { return data[i]; } std::tuple<int,int> Size() const { return std::make_tuple(col, row); } double Determinant() const { if (col != row) throw std::exception("Matrix must be square"); Matrix tempMatrix = *this; std::tuple<Matrix, Matrix> LU = LUDecomposition(tempMatrix); // 原代码此处缺少行列式计算逻辑与返回值 } }; std::tuple<Matrix, Matrix> LUDecomposition(Matrix& matrix) { std::tuple<int, int> size = matrix.Size(); int col = std::get<0>(size); int row = std::get<1>(size); Matrix lower(col, row); Matrix upper(col, row); for (int i = 0; i < col; i++) { for (int k = i; k < col; k++) { // 原代码此处sum定义为int会丢失浮点精度 int sum = 0; for (int j = 0; j < i; j++) { sum += lower[j][i] * upper[k][j]; } upper[k][i] = matrix[k][i] - sum; } for (int k = i; k < col; k++) { if (i == k) lower[i][i] = 1; else { // 同上,sum类型存在精度问题 int sum = 0; for (int j = 0; j < i; j++) { sum += lower[j][k] * upper[i][j]; } lower[i][k] = (matrix[i][k] - sum) / upper[i][i]; } } } return std::make_tuple(lower, upper); }
解决方案
两种方案均可实现需求,可根据是否需要保留非成员函数形态选择:
方案1:保留非成员函数,通过前置声明解决编译依赖
注意:C++语法允许在类前置声明后,声明以该类的引用/指针作为参数的函数(引用/指针类型不要求类是完整类型),只要函数实现放在类完整定义之后即可,该方案完全适配当前场景,操作步骤如下:
- 在类定义前先前置声明
Matrix类 - 紧接着声明
LUDecomposition函数,让类内调用时能找到函数声明 - 保持Matrix类的完整定义不变
- 将LUDecomposition的实现放在Matrix类定义之后(原代码已经是该位置,无需移动)
- 可选调整:如果后续LUDecomposition需要访问Matrix的私有成员,在Matrix类内添加友元声明
friend std::tuple<Matrix, Matrix> LUDecomposition(Matrix& matrix);即可
修改后的可编译代码结构:
#pragma once #include <vector> #include <tuple> #include <exception> // 原代码使用std::exception需引入对应头文件 enum MatrixType { Identity, Zeros, Ones }; // 前置声明Matrix类 class Matrix; // 前置声明非成员函数,引用参数允许不完整类型 std::tuple<Matrix, Matrix> LUDecomposition(Matrix& matrix); class Matrix { // 如需LUDecomposition访问私有成员,取消下一行注释 // friend std::tuple<Matrix, Matrix> LUDecomposition(Matrix& matrix); private: int col, row; typedef std::vector<double> Row; std::vector<Row> data; // 补充原代码缺失的私有成员声明 void MakeIdentity() {} void Fill(double val) {} public: Matrix(int columns, int rows): row(rows), col(columns), data(columns, std::vector<double>(rows)) {} Matrix(int columns, int rows, MatrixType matrixType) : row(rows), col(columns), data(columns, std::vector<double>(rows)) { switch (matrixType) { case Identity: this->MakeIdentity(); break; case Zeros: this->Fill(0); break; case Ones: this->Fill(1); break; default: break; } } Row& operator[](int i) { return data[i]; } // 补充const版本下标运算符,适配const场景调用 const Row& operator[](int i) const { return data[i]; } std::tuple<int,int> Size() const { return std::make_tuple(col, row); } double Determinant() const { if (col != row) throw std::exception("Matrix must be square"); Matrix tempMatrix = *this; std::tuple<Matrix, Matrix> LU = LUDecomposition(tempMatrix); // 补充后续行列式计算逻辑 return 0.0; } }; // 类定义完成后实现LUDecomposition,此时Matrix为完整类型可正常访问成员 std::tuple<Matrix, Matrix> LUDecomposition(Matrix& matrix) { std::tuple<int, int> size = matrix.Size(); int col = std::get<0>(size); int row = std::get<1>(size); Matrix lower(col, row); Matrix upper(col, row); for (int i = 0; i < col; i++) { for (int k = i; k < col; k++) { // 修正sum类型为double避免浮点精度丢失 double sum = 0; for (int j = 0; j < i; j++) { sum += lower[j][i] * upper[k][j]; } upper[k][i] = matrix[k][i] - sum; } for (int k = i; k < col; k++) { if (i == k) lower[i][i] = 1; else { double sum = 0; for (int j = 0; j < i; j++) { sum += lower[j][k] * upper[i][j]; } lower[i][k] = (matrix[i][k] - sum) / upper[i][i]; } } } return std::make_tuple(lower, upper); }
方案2:将LUDecomposition改为静态成员函数
如果不要求保留非成员函数形态,直接将LUDecomposition声明为Matrix的静态成员函数是更简洁的写法,不需要额外处理前置声明逻辑:
- 在Matrix类的public区域添加静态成员函数声明
static std::tuple<Matrix, Matrix> LUDecomposition(Matrix& matrix); - 将类外的函数实现改为类静态成员格式,即函数名前添加
Matrix::限定 - 类内Determinant调用时直接写
LUDecomposition(tempMatrix)即可,也可写为Matrix::LUDecomposition(tempMatrix)
该方案的优势是无需处理复杂的前置声明依赖,静态成员函数天然拥有访问类私有成员的权限,不需要额外添加友元声明。
内容的提问来源于stack exchange,提问作者AssistantToTheRegionalManager
相关产品推荐
相关产品推荐

