天天看點

C++小例子——03 列向量類colVector

再來一個列向量類colVector。

其成員變量有兩個,元素數目,和用于動态申請釋放記憶體空間的double型指針。

其構造函數可由元素數目和元素值(列向量中所有元素都是同一個值)來構造,也可用另外一個列向量來構造(拷貝構造,copy constructor),析構函數用來釋放存儲空間,此外,還有拷貝指派(copy assignment)函數,即用操作符等号=來實作深拷貝指派操作,以及移動構造(move constructor)函數,用右值來做淺複制(僅複制指針位址),和移動指派(move constructor)函數,重載操作符等号=,用右值來做淺複制。

其他成員函數包括提取第idx個分量的值,設定第idx個分量的值,設定整體元素的值,用操作符中括号[]來擷取第idx個分量的引用(可以給第idx個元素做修改)和常引用(隻能把第idx個元素拿出來用,不能修改),以及複合運算符+=、-=、*=、/=,用于和另一個colVector或double型變量的自身加減乘除操作,友元運算符+、-、*、/用于列向量colVector和另一個列向量或标量double型之間的加減乘除運算。提供了計算兩個列向量點積的操作函數,計算列向量二範數的函數,以及機關化列向量的函數,當然都是友元函數。最後,還重載了輸入流操作符>>和輸出流操作符<<用來讀入和輸出列向量。

當然,還可以在外面定義矩陣和列向量的相乘函數,以及線性求解器用于求解Ax=B。

列向量類colVector的架構如下:

成員變量

  1. 列向量的元素數目
  2. double指針用于動态申請釋放記憶體空間,來存儲列向量元素

成員函數

  1. 構造函數1,元素數目,元素值,預設值為0
  2. 拷貝構造,由另一個列向量構造
  3. 拷貝指派,重載指派運算符=,左列向量 = 右列向量,将右列向量的值賦給左列向量
  4. 移動構造,由右值列向量構造
  5. 移動指派,重載指派運算符=,左列向量 = 右值列向量,将右值列向量的值淺複制給左列向量
  6. 析構函數,釋放記憶體空間
  7. 提取第idx個元素的值getCompIdx
  8. 設定第idx個元素的值setCompIdx
  9. 設定所有元素的值setAll
  10. 傳回第idx個元素的引用,重載operator[]實作
  11. 傳回第idx個元素的常引用,重載operator[]實作
  12. 操作符+=:列向量+=列向量/double
  13. 操作符-=:列向量-=列向量/double
  14. 操作符*=:列向量*=列向量/double
  15. 操作符/=:列向量/=列向量/double
  16. 友元操作符+:列向量+列向量,列向量+double,double+列向量
  17. 友元操作符-:列向量-列向量,列向量-double,double-列向量
  18. 友元操作符*:列向量*列向量,列向量*double,double*列向量
  19. 友元操作符/:列向量/列向量,列向量/double,double/列向量
  20. 友元函數dotProduct,計算兩個列向量的點積
  21. 友元函數norm,計算列向量的二範數(也稱模或幅值)
  22. 友元函數unit,計算列向量的機關化列向量
  23. 友元輸入符>>,讀入列向量
  24. 友元輸出符<<,輸出列向量

寫好的程式如下:

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;
}
           

測試結果,表明所有函數均實作了其功能。

C++小例子——03 列向量類colVector

繼續閱讀