C++:类中几个默认函数及其特点

本文介绍了C++类中的四个默认函数:构造函数、析构函数、拷贝构造函数和赋值运算符重载函数。详细阐述了它们的作用、使用场景以及注意事项,如构造函数和析构函数的调用时机,拷贝构造函数和赋值运算符重载函数的深拷贝与浅拷贝问题。

类中有六个默认函数:

1、构造函数

2、析构函数

3、拷贝构造函数

4、赋值运算符重载函数

5、取地址操作符的重载函数

6、const修饰的取地址操作符的重载函数

以下是简单实现了一个商品CGoods的类,类中是基本的4个成员函数:

class  CGoods
{
public:
	CGoods()
	{}
        ~CGoods()
        {}
        CGoods(const CGoods& rhs);
        CGoods& operator=(const CGoods& rhs);
private:
	char* mname;
	float mprice;
	int mamount;
};

1、构造函数

        对象的生成一般分为两步:

                1、系统开辟内存

                2、系统调用构造函数给内存做初始化

构造函数:函数名 = 类名,作用是给开辟的内存做初始化。由于类的成员方法依赖对象调用,构造完成后才生成对象,所以构造函数无法手动调用,只能系统调用

构造函数可以自己写,也可以使用系统默认的构造函数。若用户提供构造函数,系统就不会提供;若没有,则使用系统提供的构造函数。由此可见,构造函数可以重载

CGoods()//系统提供的默认构造函数
{}
CGoods(char* name, float price, int amount)//用户自定义的构造函数
{
	mname = new char[strlen(name) + 1];
	strcpy(mname, name);
	mprice = price;
	mamount = amount;
}

构造函数的使用:

CGoods good1;//使用默认的构造函数,只是生成一个对象
CGoods good2("rice",2,100);//使用自定义的构造函数,并进行初始化

CGoods good3();//函数声明,并没有生成对象

2、析构函数

       对象的销毁一般也分为两步:

               1、调用析构函数释放对象所占用的其他资源;

               2、释放内存

析构函数:函数名 = ~类名,作用是释放对象所占用的其他资源。由于析构函数调用前对象已经存在,所以析构函数可以手动调用,手动调用析构函数时,析构函数会退化成一个普通成员方法,之后系统还会再调用一次析构函数。

析构函数可以自己写。若用户提供析构函数,则使用用户提供的;若没有,则使用系统默认的析构函数。由于资源与内存只能释放一次,所以析构函数不支持重载

~CGoods()//系统默认的构造函数
{}
~CGoods()//用户自定义构造函数
{
	delete[] mname;
	std::cout << this << "CGoods::~CGoods()" << std::endl;
		
	mname = NULL;
}

3、拷贝构造函数

拷贝构造函数:函数名 = 类名,作用是拿一个已存在的对象来生成一个相同类型的新对象

CGoods good1("car1", 100000, 10);//生成对象good1
CGoods good2 = good1;//用已存在的对象good1来生成对象good2
                     //相当于CGoods good2(good1);

默认的拷贝构造函数是浅拷贝,只是实现了简单的数值的拷贝,若有指针类型存在,会造成两个对象的指针指向同一个内存块,导致同一个内存块重复释放,结果出错。

CGoods(const CGoods& rhs)
{
	mname = rhs.mname;
	mprice = rhs.mprice;
	mamount = rhs.mamount;
}

若类中有指针类型,则考虑实现深拷贝,使每个指针都指向各自的内存块,再进行拷贝赋值,避免内存的重复释放。

CGoods(const CGoods& rhs)
{
	mname = new char[strlen(rhs.mname) + 1];
	strcpy(mname, rhs.mname);
	mprice = rhs.mprice;
	mamount = rhs.mamount;
}

拷贝构造函数 CGoods(const  CGoods & rhs)中,& 是必须的吗

由上图可见,若没有 &引用符号,拷贝构造函数将生成 rhs 形参对象,由于生成形参对象的过程中也调用拷贝构造函数,函数会递归陷入死循环,形参对象无法生成。有 &引用符号时,引用只是给对象起别名,不会生成新的对象。

4、赋值运算符重载函数

赋值运算符重载函数:函数名 = operator= ,作用是拿一个已存在的对象给另一个已存在的对象赋值。

CGoods good1("car1", 100000, 10);//构造生成一个对象
CGoods  good3;//构造生成另一个对象对象
good3 = good1;//用一个已存在对象给另一个已存在对象赋值

默认的拷贝构造函数是浅拷贝,只是实现了简单的数值的拷贝,若有指针类型存在,会造成两个对象的指针指向同一个内存块,导致同一个内存块重复释放,结果出错。

CGoods operator=(const CGoods& rhs)
{
	if (this == &rhs)//自赋值判断,防止出现 good1 = good1 的情况
	{
		return *this;
	}
	mname = rhs.mname;
	mprice = rhs.mprice;
	mamount = rhs.mamount;
        return *this;
}

由于该类中含有指针类型,浅拷贝会导致两个指针指向同一块内存,对象析构时重复释放出错,所以要考虑实现深拷贝:

CGoods& operator=(const CGoods& rhs)//CGoods* const this
{
    if (this != &rhs)
    {
        delete[] mname;
        mname = new char[strlen(rhs.mname) + 1];
        strcpy(mname, rhs.mname);
	mprice = rhs.mprice;
        mamount = rhs.mamount;
    }
    return *this;
}

由此可见,赋值运算符重载函数的实现有4步:

        1、自赋值判断(判断是否自己给自己赋值)

        2、释放旧资源

        3、开辟新资源

        4、赋值

赋值运算符重载函数中 CGoods& operator=(const CGoods& rhs) 形参的 & 是必须的吗

赋值运算符重载函数中的&引用不是必须的,没有的话会生成一个临时对象,多了两个函数的调用:构造、析构。有的话不会生成临时对象,免去这过程,更高效。

 

 

 

 

 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值