再來一個列向量類colVector。
其成員變量有兩個,元素數目,和用于動态申請釋放記憶體空間的double型指針。
其構造函數可由元素數目和元素值(列向量中所有元素都是同一個值)來構造,也可用另外一個列向量來構造(拷貝構造,copy constructor),析構函數用來釋放存儲空間,此外,還有拷貝指派(copy assignment)函數,即用操作符等号=來實作深拷貝指派操作,以及移動構造(move constructor)函數,用右值來做淺複制(僅複制指針位址),和移動指派(move constructor)函數,重載操作符等号=,用右值來做淺複制。
其他成員函數包括提取第idx個分量的值,設定第idx個分量的值,設定整體元素的值,用操作符中括号[]來擷取第idx個分量的引用(可以給第idx個元素做修改)和常引用(隻能把第idx個元素拿出來用,不能修改),以及複合運算符+=、-=、*=、/=,用于和另一個colVector或double型變量的自身加減乘除操作,友元運算符+、-、*、/用于列向量colVector和另一個列向量或标量double型之間的加減乘除運算。提供了計算兩個列向量點積的操作函數,計算列向量二範數的函數,以及機關化列向量的函數,當然都是友元函數。最後,還重載了輸入流操作符>>和輸出流操作符<<用來讀入和輸出列向量。
當然,還可以在外面定義矩陣和列向量的相乘函數,以及線性求解器用于求解Ax=B。
列向量類colVector的架構如下:
成員變量
- 列向量的元素數目
- double指針用于動态申請釋放記憶體空間,來存儲列向量元素
成員函數
- 構造函數1,元素數目,元素值,預設值為0
- 拷貝構造,由另一個列向量構造
- 拷貝指派,重載指派運算符=,左列向量 = 右列向量,将右列向量的值賦給左列向量
- 移動構造,由右值列向量構造
- 移動指派,重載指派運算符=,左列向量 = 右值列向量,将右值列向量的值淺複制給左列向量
- 析構函數,釋放記憶體空間
- 提取第idx個元素的值getCompIdx
- 設定第idx個元素的值setCompIdx
- 設定所有元素的值setAll
- 傳回第idx個元素的引用,重載operator[]實作
- 傳回第idx個元素的常引用,重載operator[]實作
- 操作符+=:列向量+=列向量/double
- 操作符-=:列向量-=列向量/double
- 操作符*=:列向量*=列向量/double
- 操作符/=:列向量/=列向量/double
- 友元操作符+:列向量+列向量,列向量+double,double+列向量
- 友元操作符-:列向量-列向量,列向量-double,double-列向量
- 友元操作符*:列向量*列向量,列向量*double,double*列向量
- 友元操作符/:列向量/列向量,列向量/double,double/列向量
- 友元函數dotProduct,計算兩個列向量的點積
- 友元函數norm,計算列向量的二範數(也稱模或幅值)
- 友元函數unit,計算列向量的機關化列向量
- 友元輸入符>>,讀入列向量
- 友元輸出符<<,輸出列向量
寫好的程式如下:
colVector.h 頭檔案
// 2020-07-09
// class colVector - head file
// A column vector class
// Author: Guanhua Mei
#ifndef colVector_H
#define colVector_H
#include <iostream>
class colVector
{
private:
unsigned int m_nSize; // capicity of column vector, number of elems
double* m_pdColVct; // column vector array double pointer
public:
// constructors
// construct with size and val
colVector(unsigned int = 0, double = 0.0);
// copy constructor, deep copy
colVector(const colVector&);
// copy assignment, deep copy
colVector& operator=(const colVector&);
// move constructor, shallow copy while keep memory
colVector(colVector&&) noexcept;
// move assignment, shallow copy while keep memory
colVector& operator=(colVector&&) noexcept;
// destructor
~colVector();
// get value at idx
double getCompIdx(unsigned int) const;
// set value at idx
void setCompIdx(unsigned int, double = 0.0);
// set all
void setAll(double = 0.0);
// operator [] to fetch value
double& operator[](unsigned int);
const double& operator[](unsigned int) const;
// operator += -= *= /=, legality wil not be checked!!
colVector& operator+=(const colVector&);
colVector& operator+=(const double&);
colVector& operator-=(const colVector&);
colVector& operator-=(const double&);
colVector& operator*=(const colVector&);
colVector& operator*=(const double&);
colVector& operator/=(const colVector&);
colVector& operator/=(const double&);
// friend operator + - * /, legality wil not be checked!!
friend colVector operator+(const colVector&, const colVector&);
friend colVector operator+(const colVector&, const double&);
friend colVector operator+(const double&, const colVector&);
friend colVector operator-(const colVector&, const colVector&);
friend colVector operator-(const colVector&, const double&);
friend colVector operator-(const double&, const colVector&);
friend colVector operator*(const colVector&, const colVector&);
friend colVector operator*(const colVector&, const double&);
friend colVector operator*(const double&, const colVector&);
friend colVector operator/(const colVector&, const colVector&);
friend colVector operator/(const colVector&, const double&);
friend colVector operator/(const double&, const colVector&);
// dot product, legality wil not be checked!!
friend double dotProduct(const colVector&, const colVector&);
// magnitude, i.e., 2nd norm
friend double norm(const colVector&);
// unit
friend colVector unit(const colVector&);
// outputstream operator <<
friend std::ostream& operator<<(std::ostream&, const colVector&);
// inputstream operator >>
friend std::istream& operator>>(std::istream&, colVector&);
};
// For MSV 2019, need to be declared outside again! Do not know why!!
// outputstream operator <<
std::ostream& operator<<(std::ostream&, const colVector&);
// inputstream operator >>
std::istream& operator>>(std::istream&, colVector&);
#endif
colVector.cpp 檔案
// 2020-07-09
// class colVector - cpp file
#include "colVector.h"
#include <math.h>
// constructors
// construct with size and val
colVector::colVector(unsigned int nSize, double dVal):
m_nSize(nSize), m_pdColVct(nullptr)
{
//std::cout << "Construct by size and dValue. " << std::endl;
if (nSize > 0) // ask memory
m_pdColVct = new double[nSize];
for (unsigned i = 0; i < nSize; ++i) // assign value
m_pdColVct[i] = dVal;
}
// copy constructor, deep copy
colVector::colVector(const colVector& colVct)
{
//std::cout << "Copy constructor. " << std::endl;
m_nSize = colVct.m_nSize;
m_pdColVct = nullptr;
if (m_nSize > 0) // ask memory
m_pdColVct = new double[m_nSize];
for (unsigned i = 0; i < m_nSize; ++i) // assign value
m_pdColVct[i] = colVct.m_pdColVct[i];
}
// copy assignment, deep copy
colVector& colVector::operator=(const colVector& colVct)
{
//std::cout << "Copy assignment. " << std::endl;
if (this == &colVct)
return *this;
if (m_pdColVct != nullptr) // free old memory
delete[] m_pdColVct;
m_nSize = colVct.m_nSize;
if (m_nSize > 0) // ask new memory
m_pdColVct = new double[m_nSize];
for (unsigned i = 0; i < m_nSize; ++i) // copy value
m_pdColVct[i] = colVct.m_pdColVct[i];
return *this;
}
// move constructor, shallow copy while keep memory
colVector::colVector(colVector&& colVctRhs) noexcept:
m_nSize(colVctRhs.m_nSize), m_pdColVct(colVctRhs.m_pdColVct)
{
//std::cout << "move constructor" << std::endl;
colVctRhs.m_nSize = 0;
// set rhs value ptr to nullptr, thus in destructor
// its memory will be kept! Beautiful!
colVctRhs.m_pdColVct = nullptr;
}
// move assignment, shallow copy while keep memory
colVector& colVector::operator=(colVector&& colVctRhs) noexcept
{
//std::cout << "move assignment. " << std::endl;
if (this == &colVctRhs) // prevent self assignment
return *this;
// free old memory
m_nSize = 0;
if (m_pdColVct != nullptr)
delete[] m_pdColVct;
// move pointers
m_nSize = colVctRhs.m_nSize;
m_pdColVct = colVctRhs.m_pdColVct;
// let right hand side object null so destructor will keep memory
colVctRhs.m_nSize = 0;
colVctRhs.m_pdColVct = nullptr;
// return
return *this;
}
// destructor
colVector::~colVector()
{
//std::cout << "Destructor. " << *this << std::endl;
if (m_pdColVct != nullptr) // free memory
delete[] m_pdColVct;
m_pdColVct = nullptr;
m_nSize = 0;
}
// get value
double colVector::getCompIdx(unsigned int nIdx) const
{
if (nIdx < m_nSize)
return m_pdColVct[nIdx];
else
return 0.0; // no error message will output or exit
}
// set value
void colVector::setCompIdx(unsigned int nIdx, double val)
{
if (nIdx < m_nSize) // only correct position will be set value
m_pdColVct[nIdx] = val;
}
// set all
void colVector::setAll(double val)
{
for (unsigned i = 0; i < m_nSize; ++i)
m_pdColVct[i] = val;
}
// operator [] to fetch value
double& colVector::operator[](unsigned int nIdx)
{
return m_pdColVct[nIdx]; // do not check if nIdx is correct
}
const double& colVector::operator[](unsigned int nIdx) const
{
return m_pdColVct[nIdx]; // do not check if nIdx is correct
}
// operator += -= *= /=, legality wil not be checked!!
colVector& colVector::operator+=(const colVector& colVct)
{
for (unsigned int i = 0; i < m_nSize; ++i)
m_pdColVct[i] += colVct.m_pdColVct[i];
return *this;
}
colVector& colVector::operator+=(const double& dVal)
{
for (unsigned int i = 0; i < m_nSize; ++i)
m_pdColVct[i] += dVal;
return *this;
}
colVector& colVector::operator-=(const colVector& colVct)
{
for (unsigned int i = 0; i < m_nSize; ++i)
m_pdColVct[i] -= colVct.m_pdColVct[i];
return *this;
}
colVector& colVector::operator-=(const double& dVal)
{
for (unsigned int i = 0; i < m_nSize; ++i)
m_pdColVct[i] -= dVal;
return *this;
}
colVector& colVector::operator*=(const colVector& colVct)
{
for (unsigned int i = 0; i < m_nSize; ++i)
m_pdColVct[i] *= colVct.m_pdColVct[i];
return *this;
}
colVector& colVector::operator*=(const double& dVal)
{
for (unsigned int i = 0; i < m_nSize; ++i)
m_pdColVct[i] *= dVal;
return *this;
}
colVector& colVector::operator/=(const colVector& colVct)
{
for (unsigned int i = 0; i < m_nSize; ++i)
m_pdColVct[i] /= colVct.m_pdColVct[i];
return *this;
}
colVector& colVector::operator/=(const double& dVal)
{
for (unsigned int i = 0; i < m_nSize; ++i)
m_pdColVct[i] /= dVal;
return *this;
}
// friend + - * /, legality will not be checked!
colVector operator+(const colVector& lhs, const colVector& rhs)
{
colVector colVctTmp(lhs);
colVctTmp += rhs;
return colVctTmp;
}
colVector operator+(const colVector& lhs, const double& dVal)
{
colVector colVctTmp(lhs);
colVctTmp += dVal;
return colVctTmp;
}
colVector operator+(const double& dVal, const colVector& rhs)
{
colVector colVctTmp(rhs);
colVctTmp += dVal;
return colVctTmp;
}
colVector operator-(const colVector& lhs, const colVector& rhs)
{
colVector colVctTmp(lhs);
colVctTmp -= rhs;
return colVctTmp;
}
colVector operator-(const colVector& lhs, const double& dVal)
{
colVector colVctTmp(lhs);
colVctTmp -= dVal;
return colVctTmp;
}
colVector operator-(const double& dVal, const colVector& rhs)
{
colVector colVctTmp(rhs.m_nSize, dVal);
colVctTmp -= rhs;
return colVctTmp;
}
colVector operator*(const colVector& lhs, const colVector& rhs)
{
colVector colVctTmp(lhs);
colVctTmp *= rhs;
return colVctTmp;
}
colVector operator*(const colVector& lhs, const double& dVal)
{
colVector colVctTmp(lhs);
colVctTmp *= dVal;
return colVctTmp;
}
colVector operator*(const double& dVal, const colVector& rhs)
{
colVector colVctTmp(rhs.m_nSize, dVal);
colVctTmp *= rhs;
return colVctTmp;
}
colVector operator/(const colVector& lhs, const colVector& rhs)
{
colVector colVctTmp(lhs);
colVctTmp /= rhs;
return colVctTmp;
}
colVector operator/(const colVector& lhs, const double& dVal)
{
colVector colVctTmp(lhs);
colVctTmp /= dVal;
return colVctTmp;
}
colVector operator/(const double& dVal, const colVector& rhs)
{
colVector colVctTmp(rhs.m_nSize, dVal);
colVctTmp /= rhs;
return colVctTmp;
}
// dot product
double dotProduct(const colVector& lhs, const colVector& rhs)
{
double dVal = 0.0;
for (unsigned int i = 0; i < lhs.m_nSize; ++i)
dVal += (lhs.m_pdColVct[i] * rhs.m_pdColVct[i]);
return dVal;
}
// magnitude, i.e., 2nd norm
double norm(const colVector& colVct)
{
return sqrt(dotProduct(colVct, colVct));
}
// unit
colVector unit(const colVector& colVct)
{
return (colVct / norm(colVct));
}
// operator <<
std::ostream& operator<<(std::ostream& os, const colVector& colVct)
{
if (colVct.m_nSize == 0)
os << "Empty Column Vector! ";
else
{
os << "[";
for (unsigned int i = 0; i < colVct.m_nSize - 1; ++i)
os << colVct[i] << "; ";
os << colVct[colVct.m_nSize - 1] << "]";
}
return os;
}
// operator >>
std::istream& operator>>(std::istream& is, colVector& colVct)
{
if (colVct.m_nSize != 0)
{
colVct.m_nSize = 0;
delete [] colVct.m_pdColVct; // free memory
colVct.m_pdColVct = nullptr;
}
is >> colVct.m_nSize;
if (!is)
{
colVct.m_nSize = 0;
return is;
}
colVct.m_pdColVct = new double[colVct.m_nSize];
for (unsigned int i = 0; i < colVct.m_nSize; ++i)
{
is >> colVct.m_pdColVct[i];
if (!is)
colVct.m_pdColVct[i] = 0.0;
}
return is;
}
測試主函數main.cpp
// 2020-07-09
// main function - test class colVector
// Author: Guanhua Mei
#include <iostream>
#include "colVector.h"
using namespace std;
int main()
{
colVector colVct1;
cout << colVct1 << endl;
colVector colVct2(2, 3.14);
cout << colVct2 << endl;
cout << "Please input a column vector in format "
<< "nSize a0 a1 a2 ... aN: " << endl;
cin >> colVct1;
cout << colVct1 << endl;
colVector colVct3(2, 9);
colVct3.setCompIdx(0, 3);
colVct3.setCompIdx(1, 4);
colVct2.setCompIdx(0, 1);
colVct2.setCompIdx(1, 2);
cout << "colVct2: " << colVct2 << endl;
cout << "colVct3: " << colVct3 << endl;
colVector colVct4(colVct3);
cout << colVct4 << endl;
colVct4.setAll(9);
cout << colVct4 << endl;
cout << colVct3.getCompIdx(0) << endl;
cout << colVct3[1] << endl;
cout << (colVct3 += 1.0) << endl;
cout << (colVct3 -= 1.0) << endl;
cout << (colVct3 *= 2.0) << endl;
cout << (colVct3 /= 2.0) << endl << endl;
cout << (colVct3 += colVct2) << endl;
cout << (colVct3 -= colVct2) << endl;
cout << (colVct3 *= colVct2) << endl;
cout << (colVct3 /= colVct2) << endl << endl;
cout << (colVct3 + colVct2) << endl;
cout << (colVct3 - colVct2) << endl;
cout << (colVct3 * colVct2) << endl;
cout << (colVct3 / colVct2) << endl << endl;
cout << (colVct3 + 1.0) << endl;
cout << (colVct3 - 1.0) << endl;
cout << (colVct3 * 2.0) << endl;
cout << (colVct3 / 2.0) << endl << endl;
cout << (1.0 + colVct3) << endl;
cout << (1.0 - colVct3) << endl;
cout << (2.0 * colVct3) << endl;
cout << (2.0 / colVct3) << endl << endl;
cout << dotProduct(colVct2, colVct3) << endl;
cout << norm(colVct3) << endl;
cout << unit(colVct3) << endl;
return 0;
}
測試結果,表明所有函數均實作了其功能。