构造函数与析构函数

「C++ 40 周年」主题征文大赛(有机会与C++之父现场交流!) 10w+人浏览 140人参与

构造函数与析构函数

默认构造函数

​ 默认构造函数有以下两种结构可以使用:

Role() = default; 
Role() {}; // 当需要代码时,使用这种方法

​ 当需要代码时,使用第二个结构;当不需要代码且要保留类中的默认构造函数时,就使用第一个结构,其效率相比于第二种更好。

explicit关键字

​ 当成员函数的参数位类对象本身时,若有合适的构造函数,使用构造函数内的参数也可以通过隐式类型转化构造出一个临时变量(类)来传入到成员函数中。

​ 例如:

// Role的public中
inline bool bigger(Role role)
{
    return role.lv > lv; 
}

Role(int _lv = 1)
{
    lv = _lv;
    std::cout << "LV:" << lv << std::endl; 
}

// main.cpp
int main()
{
	Role user(100); 
	Role master(10);

	cout << user.bigger(master) << endl; 

	cout << user.bigger(520) << endl;

	return 0;
}

​ 其最终输出结果为:

image-20251106165410864

​ 可见确实在调用bigger成员函数时,传入参数520通过调用构造函数得到一个临时变量类,从而与user进行比较。

若不想出现隐式类型转换的情况,可以使用explicit来修饰成员函数,从而禁止成员函数进行隐式类型转换。

经测试,也可以将成员函数的Role role参数改成Role& role,改成引用类型也不可以进行隐式类型转换。

成员初始化列表

​ 成员初始化列表相比于直接在构造函数中初始化成员变量有两个好处:

  1. 效率更高
  2. 在某些情况下,必须要使用这种方法(继承)

​ 例子:

// mian.cpp
int main()
{
	//Role user(); 

	Role master(50, 200);

	return 0;
}

// Role.h
Role(int _lv, int _damage) 
{
    std::cout << "LV:" << lv << " Damage:" << damage << std::endl;
    lv = _lv;
    damage = _damage;
    std::cout << "LV:" << lv << " Damage:" << damage << std::endl;
}

​ 结果:

image-20251106184626197

​ 当使用成员初始化列表时:

Role(int _lv, int _damage) : lv(_lv), damage(_damage)
{
    std::cout << "LV:" << lv << " Damage:" << damage << std::endl;
    std::cout << "LV:" << lv << " Damage:" << damage << std::endl;
}

​ 结果:

image-20251106184748853

​ 这里给出为什莫成员初始化列表更快的原因:成员初始化列表实在成员初始化时,按照成员变量在类中的顺序进行初始化的,而在构造函数中赋值会多一些额外的操作,会先对成员变量执行默认构造函数,然后再进行复制,而成员初始化列表会直接使用成员变量的构造函数。

​ 由于成员初始化列表的赋值顺序,因此在成员初始化列表中要注意顺序,否则会出现以下的情况。当要初始化DamageCount时,lv并没有初始化,因此DamageCount就为不确定的值,因此最终输出的DamageCount也就不确定。

Role(int _lv, int _damage) : DamageCount(lv * 10),lv(_lv), damage(_damage)
{
    std::cout << "LV:" << lv << " Damage:" << damage << " DamageCount:" << DamageCount << 	  std::endl;
    /*lv = _lv;
    damage = _damage;*/
    std::cout << "LV:" << lv << " Damage:" << damage << " DamageCount:" << DamageCount <<     std::endl;
}
image-20251106185929598

委托构造函数

​ 委托构造函就是在构造函数中使用其他构造函数,但是只能使用一个其他的构造函数,不能再加其他构造函数和成员初始化列表。

Role(int _lv, int _damage) : Role(_lv)/*DamageCount(lv * 10),lv(_lv), damage(_damage)*/
{	
    DamageCount = lv * 10;
    damage = _damage;
    std::cout << "LV:" << lv << " Damage:" << damage << " DamageCount:" << DamageCount << std::endl;
    /*lv = _lv;
    damage = _damage;*/
    std::cout << "LV:" << lv << " Damage:" << damage << " DamageCount:" << DamageCount << std::endl;
}

副本构造函数

​ 也叫拷贝构造函数,当使用另一个同类对象来赋值本对象时,会调用副本构造函数,同时如果没有给定副本构造函数,则编译器会自动生成一个副本构造函数,这个默认的副本构造函数会直接进行完全的拷贝。

​ 副本构造函数的类型为:

Role(Role& role) 
{
    // 使用初始化列表或者赋值成员变量
}

​ 举例:

// main.cpp
int main()
{
	//Role user(); 

	Role master(50, 200);
	cout << master.Getlv() << ' ' << master.GetDamageCount() << ' ' << master.GetDamage() << endl;

	// 对象为构造之前,使用同类型的其他对象,便会使用副本构造函数
	Role user(master); // 也是使用了副本构造函数

	//user = master; // 没有使用副本构造函数

	cout << user.Getlv() << ' ' << user.GetDamageCount() << ' ' << user.GetDamage() << endl;

	return 0;
}

// 副本构造函数 
	Role(Role& role)
	{
		lv = -1;
		damage = -2;
		DamageCount = -3; 
		std::cout << "使用了副本构造函数" << std::endl;
	}

​ 当不使用副本构造函数时,main函数运行结果为:

image-20251106204102558

​ 当使用副本构造函数时,main函数运行结果为:

image-20251106204143263

析构函数

​ 当我们使用对象时,在成员变量中可能会申请空间,有申请利用就删除销毁,因此就需要析构函数,其结构为:

~Role() {}

~Role() = default; // 默认析构函数

​ 要注意的是,析构函数不能够重载且没有参数。

​ 举例:

class Role
{
public:
	Role()
	{
		arry = new int[100];
		cout << "构造函数" << endl; 
	}

	~Role()
	{
		delete[] arry; // 释放资源
		cout << "析构函数" << endl; 
	}
};

int main()
{
	int a = 1;
	Role user; 

	while (a)
	{
		cin >> a; 
	}

	cout << "ending" << endl; 
	return 0;
}

​ 结果为:

image-20251106205849721

​ 可以得知,析构函数会在类生命周期结束时调用析构函数。

hstring字符串设计

image-20251107094459765

​ 实现结果:

#include <iostream>

using namespace std;

class hstring
{
public:
	hstring()
	{
		len = 1;
		str = new char[1]{ 0 }; // 这样先使字符串为空
	}

	hstring(const char* s)
	{
		len = strlen(s);
		str = new char[len + 1];
		memcpy(str, s, len);
		str[len] = '\0';
		
		//cout << "普通构造函数" << endl; 
	} 

	hstring(const hstring& h) : hstring(h.c_str())
	{
		//cout << "副本构造函数" << endl; 
	}

	char* c_str() const
	{
		return str; 
	}

	int length() const
	{
		return len; 
	}

	int size() const 
	{
		return len; 
	}

	void Setstr(const char* s) // 重新设置字符串
	{
		int slen = strlen(s); 
		if (slen > len)
		{
			delete[] str; 
			str = new char[slen + 1];
		}

		len = slen; 
		memcpy(str, s, len);
		str[len] = '\0';
	}

	~hstring()
	{
		len = 0;
		delete[] str; 
	}
private:
	char* str;		  // 字符串
	unsigned int len; // 长度
};

int main()
{
	hstring str = "你好!";

	str.Setstr("welcome C++!");


	cout << str.length() << endl; 
	cout << str.c_str() << endl; 


	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值