构造/析构/赋值运算(一)

构造/析构/赋值运算

Constructors,Destructors,and Assignment Operators

5.了解C++默认成员函数

Know what functions C++ silently writes and calls.

  1. C++默认成员函数有哪些?
    在这里插入图片描述
  2. 默认析构函数是个non-virtual,除非这个class的bass class自身声明有virtual析构函数。
  3. 如果默认拷贝构造需要拷贝的成员是内置类型,那么会以“拷贝源对象的每一个bits”来完成初始化。如果拷贝的对象不是内置类型(如string类型),那么拷贝会调用string的拷贝构造来完成。
  4. 默认copy assignment会在不违反C++语言特性的基础上为程序员完成对象拷贝。
class Object{
public:
	Object(string& s,const T& value);
	string& s;
	const T object_value; 
};
......
std::string str1("Hello");
srd::string str2("Gun");
Object<std::string,int> o1(str1,666);
Object<std::string,int> o2(str2,438);
o1=o2;//调用默认的赋值运算符是不会得逞的。

o1的成员string&是reference,不能改指向不同对象,o1的成员const T具有const属性,也不能被改变。

除构造函数外,其余成员函数调用过程都需要使用隐含的this指针去完成调用。

关于C++中默认的成员函数相关知识,推荐阅读:http://c.zhizuobiao.com/c-19012100036/

6.如果不想使用编译器默认生成的函数,就该明确拒绝

Explicitly disallow the use of compiler-generated functions you do not want.

  1. 将默认函数声明私有化(private类型函数),并且不定义(防止friend函数调用,直接不实现)。
#include<iostream>
class No_copy {
private:
	No_copy(No_copy&);
	No_copy& operator=(const No_copy&);
};

拷贝构造和重载赋值操作符对象自身可见,友元函数可见,但是我的函数并未实现,也不能调用。
2.

class No_copy{
protected:
	No_copy (){}
	~No_copy (){}
private:
	No_copy (const No_copy &);
	No_copy& operator=(const No_copy &);
};
 
class No_copy_son:private No_copy 
{
	.......
};

派生类无法调用基类的私有成员函数,无法实现拷贝或者赋值。
3. C++11太人性化,没天理。

#include<iostream>
class No_copy {
private:
	No_copy(No_copy&)=delete;
	No_copy operator=(const No_copy&)=delete;
};

7.为多态基类声明virtual析构函数

Declare destructors virtual in polymorphic base classes.

  1. 析构函数最好是虚函数。 在多态场景下,如果析构函数不是virtual的,通过base class指针删除derived class,会出现结果未定义,通常发生的是derived class未被销毁。而销毁掉了base class对象,形成资源泄漏等问题。
#include<iostream>
class Father {
public:
	Father()
	{	
		father_ptr = new char[10];
		std::cout << "Father()" << std::endl;
	}
	~Father()
	{	
		delete[] father_ptr;
		std::cout << "~Father()" << std::endl;
	}
private:
	char* father_ptr;
};
class Son :public Father
{
public:
	Son()
	{
		son_ptr = new char[5];
		std::cout << "Son()" << std::endl;
	}
	~Son()
	{
		delete[] son_ptr;
		std::cout << "~Son()" << std::endl;
	}
private:
	char* son_ptr;
};

int main()
{
	Father* pp = new Son;
	delete pp;
}
Father()
Son()
~Father()

F:\代码\Project1\Debug\Project1.exe (进程 10520)已退出,返回代码为: 0。
若要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口...

析构函数没有定义成虚函数,造成了内存泄漏。

  1. 只有当class内含有至少一个virtual函数,才为它声明virtual析构函数。classes的设计目的不是作为base classes使用,或不是为了具备多态性,就不该声明virtual析构函数(增加vptr会增加对象大小)。
  2. STL的string、vector、list等容器均是non virtual析构函数,不要企图让这些容器作为base class。
  3. 有时候令class带有纯虚析构函数,可能颇为便利。最好对纯虚析构函数进行定义,因为derived class析构函数会调用base的析构函数。

8.别让异常逃离析构函数

Prevent exception from destructors.

  1. 如果析构函数抛出异常会过早结束或者出现不明确行为。C++很不喜欢析构函数抛出异常。
  2. 如果析构函数必须执行一个动作,而该动作可能会在失败时抛出异常。那么最好赋予客户一个处理异常的机会。而如果在客户处理“因该操作发生的异常”之后,仍然无法避免异常,那么最终只有“强迫结束程序”或者“吞下异常”。
class DBConn{
public:
	void close()
	{
		db.close();
		closed=true;
	}
	~DBConn()
	{
		if(!closed){
			try{
				db.close();
			}
			catch(...){
				//abort()强迫结束程序,可抢先制止不明确行为
				//或者记录异常行为吞下异常
			}			
		}
	}
private:
	DBConnection db;
	bool closed;
};
  • 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个基于动态数组的矩阵的实现,包括构造析构、拷贝、赋值等基本操作,以及矩阵的按元素加减乘除运算,矩阵的乘法、转置和求逆等运算: ```c++ #include <iostream> #include <vector> using namespace std; class Matrix { private: int row; int col; vector<vector<double>> data; public: // 构造函数 Matrix(int r, int c, double val = 0) { row = r; col = c; data.resize(row, vector<double>(col, val)); } // 拷贝构造函数 Matrix(const Matrix &other) { row = other.row; col = other.col; data = other.data; } // 析构函数 ~Matrix() {} // 赋值运算符 Matrix &operator=(const Matrix &other) { if (this != &other) { row = other.row; col = other.col; data = other.data; } return *this; } // 矩阵按元素加法 Matrix operator+(const Matrix &other) const { if (row != other.row || col != other.col) { throw "矩阵加法维度不匹配!"; } Matrix result(row, col); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { result.data[i][j] = data[i][j] + other.data[i][j]; } } return result; } // 矩阵按元素减法 Matrix operator-(const Matrix &other) const { if (row != other.row || col != other.col) { throw "矩阵减法维度不匹配!"; } Matrix result(row, col); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { result.data[i][j] = data[i][j] - other.data[i][j]; } } return result; } // 矩阵按元素乘法 Matrix operator*(const Matrix &other) const { if (row != other.row || col != other.col) { throw "矩阵乘法维度不匹配!"; } Matrix result(row, col); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { result.data[i][j] = data[i][j] * other.data[i][j]; } } return result; } // 矩阵按元素除法 Matrix operator/(const Matrix &other) const { if (row != other.row || col != other.col) { throw "矩阵除法维度不匹配!"; } Matrix result(row, col); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { if (other.data[i][j] == 0) { throw "矩阵除法除数不能为0!"; } result.data[i][j] = data[i][j] / other.data[i][j]; } } return result; } // 矩阵乘法 Matrix operator*(const Matrix &other) const { if (col != other.row) { throw "矩阵乘法维度不匹配!"; } Matrix result(row, other.col); for (int i = 0; i < row; i++) { for (int j = 0; j < other.col; j++) { for (int k = 0; k < col; k++) { result.data[i][j] += data[i][k] * other.data[k][j]; } } } return result; } // 矩阵转置 Matrix transpose() const { Matrix result(col, row); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { result.data[j][i] = data[i][j]; } } return result; } // 矩阵求逆 Matrix inverse() const { if (row != col) { throw "非方阵不可求逆!"; } int n = row; Matrix A(*this); Matrix B(n, n); B.eye(); for (int k = 0; k < n; k++) { double max = abs(A.data[k][k]); int index = k; // 找到最大元素所在的行 for (int i = k + 1; i < n; i++) { if (abs(A.data[i][k]) > max) { max = abs(A.data[i][k]); index = i; } } // 如果最大元素为0,则该矩阵不可逆 if (max == 0) { throw "该矩阵不可逆!"; } // 交换第k行和第index行 if (index != k) { for (int j = 0; j < n; j++) { swap(A.data[k][j], A.data[index][j]); swap(B.data[k][j], B.data[index][j]); } } // 使A[k][k]为1 double d = A.data[k][k]; for (int j = 0; j < n; j++) { A.data[k][j] /= d; B.data[k][j] /= d; } // 使A[k][j](j!=k)为0 for (int i = k + 1; i < n; i++) { double d = A.data[i][k]; for (int j = 0; j < n; j++) { A.data[i][j] -= d * A.data[k][j]; B.data[i][j] -= d * B.data[k][j]; } } } // 使A[j][k](j!=k)为0 for (int k = n - 1; k > 0; k--) { for (int i = k - 1; i >= 0; i--) { double d = A.data[i][k]; for (int j = 0; j < n; j++) { A.data[i][j] -= d * A.data[k][j]; B.data[i][j] -= d * B.data[k][j]; } } } return B; } // 单位矩阵 void eye() { if (row != col) { throw "非方阵不可转化为单位矩阵!"; } for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { data[i][j] = (i == j) ? 1 : 0; } } } // 输出矩阵元素 void print() const { for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { cout << data[i][j] << "\t"; } cout << endl; } } }; ``` 在这个矩阵中,我们使用了动态二维数组来存储矩阵的数据。在构造函数中,我们使用了resize()函数来动态分配内存。在拷贝构造函数和赋值运算符中,我们直接复制了矩阵的行列数和数据,而不是使用浅拷贝。 在矩阵的按元素加减乘除运算中,我们首先检查了两个矩阵的维度是否匹配,然后按照对应元素相加减乘除的方式计算结果,并返回一个新的矩阵对象。 在矩阵的乘法运算中,我们首先检查了两个矩阵的维度是否匹配,然后按照矩阵乘法的定义计算结果,并返回一个新的矩阵对象。 在矩阵的转置和求逆运算中,我们使用了一些常见的线性代数算法来实现。需要注意的是,在求逆运算中,我们使用了高斯-约旦消元法来求解矩阵的逆矩阵,该算法的时间复杂度为O(n^3)。 最后,我们还实现了一个输出矩阵元素的函数print(),用于调试和测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值