C++构造函数、析构函数、拷贝构造函数、赋值运算函数、运算符重载基本介绍

构造函数

析构函数

为什么需要写析构函数

构造函数用于创建对象,而析构函数是用来撤销对象。简单的说:一个对象出生的时候,使用构造函数,死掉的时候,使用析构函数。
当一个类没有定义析构函数的时候,系统会自动调用缺省的析构函数。当类中存在析构函数时,变用自定义的析构函数进行对象内存的释放。

什么时候需要自定义析构函数

类的数据成员为指针且动态派生空间时需要自定义析构函数,此时用缺省的析构函数无法释放派生的内存空间。
程序调用缺省的析构函数:

class ex1{
public:
    ex1(int v = 0){x = v;}
private:
    int x;
};

缺省的析构函数为:

~ex1(){}

需要自定义析构函数:

class ex2{
public:
    ex2(int v = 0){x = new int(v);}
    ~ex2(){delete x;}
private:
    int *x;
};

当类的数据成员为指针但没有派生空间时可以使用缺省的析构函数:

class ex3{
public:
    ex3(int& v ){x = &v;}
private:
    int *x;
};

对象的初始化与撤销

ex2.h

class ex2{
public:
    ex2(int v = 0){x = new int(v);cout<<"构造对象:"<<*x<<endl;}
    int getx(){return *x;}
    void setx(int v){*x = v;}
    ~ex2(){cout<<"析构对象:"<<*x<<endl;delete x;}
private:
    int *x;
};

text.cpp

#include "ex2.h"
int main(){
ex2 objA(-1),objB,objC(1);
cout<<"objA:"<<objA.getx()<<endl;
cout<<"objB:"<<objB.getx()<<endl;
cout<<"objC:"<<objC.getx()<<endl;
objA.setx(2);
objB.setx(3);
objC.setx(4);
cout<<"objA:"<<objA.getx()<<endl;
cout<<"objB:"<<objB.getx()<<endl;
cout<<"objC:"<<objC.getx()<<endl;
return 0;
}

输出:
在这里插入图片描述
在一般情况下(类内数据成员和函数成员具有相同的作用域),调用析构函数的次序正好与调用构造函数的次序相反。

拷贝构造函数

总结
在一般情况下(类内数据成员和函数成员具有相同的作用域),调用析构函数的次序正好与调用构造函数的次序相反。(参见析构函数部分)

赋值运算函数

缺省形式

类名& operator=(const 类名& right)
{
(*this).成员=right.成员;
return *this;
}

让我们来看一看形参的类型:
void operator=(类名 right)
void operator=(类名& right)
void operator=(const 类名& right)
void operator=(类名 right)中形参right为拷贝值,需要设计拷贝构造函数,效率低
void operator=(类名& right)中形参有权利修改实参,有安全漏洞
综上所述,void operator=(const 类名& right)最为合适。

让我们再来看一看赋值运算函数返回值的类型:
void operator=(const 类名& right)
类名 operator=(const 类名& right)
类名& operator=(const 类名& right)
void operator=(const 类名& right)返回值既不能做左值又不能做右值
类名 operator=(const 类名& right)返回值不可以做左值
类名& operator=(const 类名& right)返回值既可以做左值又能做右值

最小的类

class x{};

包含了:
缺省无参构造
缺省析构函数
缺省拷贝构造
缺省赋值运算

#include "x.h"
int main(){
x obj1,obj2(obj1),obj3;
obj3 = obj1;
return 0;
}

重载运算符

什么是运算符的重载?

运算符与自定义的类结合产生的作用。

为什么要引入运算符重载?

作用:为了实现类的多态性(多态是指一个函数名有多种含义)

运算符重载规则:
1.用户不可以定义新的运算符,只能对已存在的运算符进行重载
eg:用户不可以定义’?‘为新的运算符
2.运算符重载不能改变操作数
eg:运算符’++‘为单目运算符,不可以将它作为双目运算符
3.运算符重载不能带有默认参数(赋值重载是类机制中唯一一个会缺省给与的运算符重载)
4.运算符重载不能改变运算符的运算优先级
eg:重载运算符’+‘和’*’,乘号的运算符始终比加号的优先级高

运算符重载规则
[] = () ->必须在类内重载
>> <<必须在类外重载
.(成员访问) *(指针访问) :?(条件运算) ::(域名运算) sizeof(长度)不允许重载

返回值:
1.如果返回值可能出现在=号左边, 则只能作为左值, 返回非const引用。
2.如果返回值只能出现在=号右边, 则只需作为右值, 返回const型引用或者const型值。
3.如果返回值既可能出现在=号左边或者右边, 则其返回值须作为左值, 返回非const引用。

类内重载

class complex
{
public:
    complex(double r = 0,double i = 0);
	void display();
    complex operator+(const complex& right);//加法运算不作左值,不需要将返回值设为类型引用
private:
    double real;
	double image;
};

类外重载

class complex
{
public:
    complex(double r = 0,double i = 0);
	void display();
    friend complex operator+(const complex& left,const complex& right);
private:
    double real;
	double image;
};

complex operator-(const complex& left,const complex& right);

声明重载运算符-为complex类的友元函数,方便调用complex类的私有成员与保护成员。
也可以通过在complex类中设置接口函数来读写私有成员与保护成员
如,可以在公有成员设置get_real()函数和get_image()函数来获取real和image的值。

自增运算符的重载

complex.hpp

class complex
{
public:
    complex(double r = 0,double i = 0);
	void display();
    complex operator++();//++ complex
	complex operator++(int x);//complex ++
private:
    double real;
	double image;
};

complex.cpp

complex::complex(double r, double i) :real(r), image(i){}

void complex::display()
{
	cout << real << " ";
	if (image > 0)
		cout << "+ " << image << endl;
	else
		cout << image << endl;
}

complex complex::operator++()
{
	++real;
	return (*this);//返回的是自增后的对象
}

complex complex::operator++(int x)
{
	complex temp(*this);
	++real;
	return temp;//返回的是自增前的对象
}

函数调用:

complex item1(2,3);
item1++;//隐式调用成员函数operator++(0),后缀表达式
++item1;//隐式调用成员函数operator++(),前缀表达式
item1.operator ++(2);//显式调用成员函数operator ++(2),后缀表达式
item1.operator ++();//显式调用成员函数operator ++(),前缀表达式

输入输出流重载

complex.hpp

using namespace std;//一定要声明命名空间,否则编译会出错
class complex
{
public:
    complex(double r = 0,double i = 0);
	void display();
    friend ostream& operator<<(ostream& out, const complex& item);
	friend istream& operator>>(istream& in, complex& item);
private:
    double real;
	double image;
};

complex operator+(const complex& left, int& right);
complex operator-(const complex& left, int& right);
ostream& operator<<(ostream& out, const complex& item);
istream& operator>>(istream& in, complex& item);

complex.cpp

complex::complex(double r, double i) :real(r), image(i){}

void complex::display()
{
	cout << real << " ";
	if (image > 0)
		cout << "+ " << image << endl;
	else
		cout << image << endl;
}

ostream& operator<<(ostream& out, const complex& item)
{
	out << item.real << " ";
	if (item.image < 0)
		out << item.image << "i" << endl;
	else if (item.image > 0)
		out << "+" << item.image << "i" << endl;
	return out;
}

istream& operator>>(istream& in, complex& item)
{
	in >> item.real>>item.image;
	return in;
}

函数调用:

complex item1(2,3);
cout << item1;
cin >> item1;
cout << item1;

一些例子

通过这些例子来加深对以上这些函数的理解

complex类

complex.h

class complex
{
public:
	complex(double r = 0,double i = 0);
	complex(const complex& item);//可省略
	complex& operator=(const complex& item);//可省略
	void display();
	complex add(const complex& right);
	complex substract(const complex& right);
	~complex();//可省略
private:
	double real;
	double image;
};

complex.cpp

#include <iostream>
#include "complex.h"
using namespace std;

complex::complex(double r, double i) :real(r), image(i) 
{ cout << "build" << " " << r << " " << i << " 调用构造函数!" <<endl; }

complex::complex(const complex& item)
{
	real = item.real;
	image = item.image;
	cout << "build" << " " << real << " " << image <<" 调用拷贝构造函数!"<< endl;
}

complex& complex::operator=(const complex& item)
{
	real = item.real;
	image = item.image;
	cout << "build" << " " << real << " " << image <<" 重载等号!"<< endl;
	return (*this);
}

void complex::display()
{
	cout << real;
	if (image > 0)
		cout << "+" << image;
	else
		cout << image;
}

complex complex::add(const complex& right)
{
	real = real + right.real;
	image = image + right.image;
	return(*this);
}

complex complex::substract(const complex& right)
{
	real = real - right.real;
	image = image - right.image;
	return(*this);
}

complex::~complex() 
{ cout << "delete" << " " << real << " " << image <<" 调用析构函数!"<< endl; }

test.cpp

#include <iostream>
#include "complex.h"
using namespace std;
int main()
{
	complex item1;
	complex item2(2, 3);
	complex item3(item2);
	complex item4(4, 5);
	complex item5 = item4;
	complex item6;
	item6 = item4;
	item5.add(item2);
	item4.substract(item2);
	return 0;
}

输出:
在这里插入图片描述

①:声明时的等号不是赋值,是初始化,所以以拷贝构造的形式对对象进行初始化,而不调用重载等号的函数。
②:对对象进行赋值,调用重载等号函数。
③:如果一个函数的返回值为类类型时,这个函数需要调用拷贝构造函数去生成一个副本(临时对象,在return是被释放)。这就是为什么调用add和substract函数是会调用拷贝构造函数的原因。

完整的complex类

complex.hpp

#ifndef __COMPLEX_H__
#define __COMPLEX_H__
#include <iostream>
using namespace std;
class complex
{
public:
	complex(double r = 0, double i = 0);
	complex(const complex& item);//可省略
	complex& operator=(const complex& item);//可省略
	void display();
	double get_real()const;
	double get_image()const;
	complex add(const complex& right);
	complex substract(const complex& right);
	~complex();//可省略
	complex operator+(const complex& item);
	complex operator-(const complex& item);
	complex operator++();//++ complex
	complex operator++(int x);//complex ++
	friend complex operator+(const complex& left, int& right);
	friend complex operator-(const complex& left, int& right);
	friend ostream& operator<<(ostream& out, const complex& item);
	friend istream& operator>>(istream& in, complex& item);

private:
	double real;
	double image;
};

complex operator+(const complex& left, int& right);
complex operator-(const complex& left, int& right);
ostream& operator<<(ostream& out, const complex& item);
istream& operator>>(istream& in, complex& item);

#endif

complex.cpp

#include <iostream>
#include "complex.h"
using namespace std;

complex::complex(double r, double i) :real(r), image(i)
{
	//cout << "build" << " " << r << " " << i << " 调用构造函数!" <<endl; 
}

complex::complex(const complex& item)
{
	real = item.real;
	image = item.image;
	//cout << "build" << " " << real << " " << image <<" 调用拷贝构造函数!"<< endl;
}

complex& complex::operator=(const complex& item)
{
	real = item.real;
	image = item.image;
	//cout << "build" << " " << real << " " << image <<" 重载等号!"<< endl;
	return (*this);
}

void complex::display()
{
	cout << real << " ";
	if (image > 0)
		cout << "+ " << image << endl;
	else
		cout << image << endl;
}

double complex::get_real()const
{
	return real;
}

double complex::get_image()const
{
	return image;
}

complex complex::add(const complex& right)
{
	complex result;
	result.real = real + right.real;
	result.image = image + right.image;
	return result;
}

complex complex::substract(const complex& right)
{
	complex result;
	result.real = real - right.real;
	result.image = image - right.image;
	return result;
}

complex::~complex()
{
	//cout << "delete" << " " << real << " " << image <<" 调用析构函数!"<< endl; 
}

complex complex::operator+(const complex& item)
{
	complex result;
	result.real = real + item.real;
	result.image = image + item.image;
	return result;
}

complex complex::operator-(const complex& item)
{
	complex result;
	result.real = real - item.real;
	result.image = image - item.image;
	return result;
}

complex complex::operator++()
{
	++real;
	return (*this);//返回的是自增后的对象
}

complex complex::operator++(int x)
{
	complex temp(*this);
	++real;
	return temp;//返回的是自增前的对象

}

complex operator+(const complex& left, int& right)
{
	complex result;
	result.real = left.real + right;
	result.image = left.image;
	return result;
}

complex operator-(const complex& left, int& right)
{
	complex result;
	result.real = left.real - right;
	result.image = left.image;
	return result;
}

ostream& operator<<(ostream& out, const complex& item)
{
	out << item.real << " ";
	if (item.image < 0)
		out << item.image << "i" << endl;
	else if (item.image > 0)
		out << "+" << item.image << "i" << endl;
	return out;
	/*另一种实现方式
	double r = item.get_real();
	double i = item.get_image();
	out << r << " ";
	if (i < 0)
		out << i << "i" << endl;
	else if (i > 0)
		out << "+" << i << "i" << endl;
	return out;
	*/
}

istream& operator>>(istream& in, complex& item)
{
	in >> item.real>>item.image;
	return in;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值