C++ 类和对象+内存管理

目录

内部类

编译器的自动优化:

内存管理


怎么判断调用了几次构造函数,拷贝构造函数,析构函数?.

定义两个全局变量m,n。每调用一次构造和拷贝构造都让m,n++,把m,n的值打印出来。

b9843919a378419aaa42d57addc342ab.png5f5ae4115d4f42239097fbffcb4b9473.png

 很明显,main函数没有调用A这个类的话m,n的值没有++。

用A对象类型创建一个变量aa1,此刻再打印出来m,n的值看:

1a7b1698b7654d1194d3edcad055fa0a.pngc0d3c29d4ab94705a7d76317a454cd5b.png

 m,n的值为1,说明调用了一次构造函数。

怎么看析构完还剩多少个:

每调用析构一次就m--,m还剩多少就是还有多少个没有被析构。

写一个拷贝构造函数,一个A对象类型的函数:434d81c5471a453bb57f9937bfa78672.png

然后写一个函数调用:

我用linux下vim写一下

因为是c++,我用g++进行编译但是编译不了,然后我用YUM下载g++显示nothiing to do,说明已经下过g++了,那么肯定是g++需要更新的缘故:

使用这个命令更新gcc,++:

yum install update gcc+ gcc-c++

 更新完成之后可以编译:

调用一次函数:

发现会调用一次拷贝构造:

 这是因为调用函数就要传参,传参就要拷贝构造。

如果有这样的场景,没必要调用拷贝构造:

调用fun函数,函数再调用打印函数,打印函数只负责打印不用传参,不传参就没必要调用拷贝构造:

 因此我们可以用引用传参:

这样就只会调用构造函数了:

#include<iostream>
using namespace std;

int n = 0;
int m = 0;
class A
{ 
  public:
  A()
  {
	n++;
	m++;
  }
  A(const A& t)
  {
	  n++;
	  m++;
  }
  ~A()
  {
	  m--;
  }
};

A fun(A aa)
{
	return aa;
}
int main()
{
	A aa1;
	A aa2;
	cout<< n << " " << m << endl;

	A();
	cout << n << " " << m << endl;

	 
	fun(aa1);
	cout << n << " " << m << endl;

	return 0;
}

53a55d1b90dc4b12bebca5849ae1084f.png

解析:

但是这样有个缺点,就是m,n的值容易被修改,有风险:

7012f4fa66ef4a9e9547742a3cd6afe5.png

c8b7a6de32884eec9fa14d14b86671de.png

 把m,n作为静态变量放在class A里面:

886392bdfa7e4d30801c9777c86337b0.png

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{
		n++;
		m++;
	}
	A(const A& t)
	{
		n++;
		m++;
	}
	~A()
	{
		m--;
	}
	int Getm()
	{
		return m;
	}
	int print()
	{
		cout << m << endl;
		return Getm();

	}
private:
		static int  m, n;
};
int A::m = 0;
int A::n = 0;
A fun(A aa)
{
	return aa;
}
int main()
{
	A aa1;
	A aa2;
	

	aa1.print();
	
	//cout << A::n << " " << A::m << endl;
	//A();
	//cout << aa1.m<< " " << aa1.n<< endl;
	//fun(aa1);
	//A* pst = nullptr;
	//pst->m;
	return 0;
}


53833811d2d342a8aab704406a07904d.png

这个时候m,n就不能被直接访问了,也就无法被修改:e6c040ab8eec46d98813e165163aba32.png

只能在class A里面写函数:

class  A:

{f22a98b9b4dd4fcc93da102be5399b43.png}

然后在类外调用函数来访问m,n:
72c840e64b554b68b646cbf566e33fdc.png

如果把私有关了:2577ca36a0aa4099bb694d6c0f3537fb.png那么下面这几种调用都可以

求1+2+3+...+n_牛客题霸_牛客网 (nowcoder.com)

这个题的意思就是:b595a07a21a545dca7aca1a10d2efa63.png

 思路:用静态变量的思路:

设一个静态变量i,让i每次+1,加n次

设一个静态变量ret,ret每次+i,加n次。

利用构造函数,用类对象类型创建一个大小为n的数组,就会调用n次构造函数,这样就形成了一个n循环次数,在构造函数里写循环语句:ret+i,i++;

最后再写一个函数,返回ret。


#include <linux/limits.h>
class sum{

public:
sum()
{
ret+=i;
i++;


}

 static int print()
{
  return ret;
}


private:

static int i;
static int ret;
};
int sum::i=1;
int sum::ret=0;



class Solution {
public:
    int Sum_Solution(int n) {
    sum a[n];   
return sum::print();

    }
};

 画图解析:

385fabb4a24e47eeb61738f06bf35d52.png

内部类

所谓的内部类无非是在一个类里面包含一个类,那它与外部类有什么区别?

看下面代码,求sizeof(A)大小:21bb9e8cf84941b3b5102e4024ead76c.png

 答案:1f6f903cefc943e8a1aa6d1d93d28271.png

原因:内部类是独立的,它受类 域的限制,也就是说Class A和Class B是两个独立的类,下面这种情况才是sizeof(A)才是8:0211986baffc4886b3e034b9f2cdd287.png

c089cd875c064c5dacf1b47ce590eec3.png写了内部类之后外部不能直接访问内部类:39de66ba42ee4af6958dbc436f0259ff.png

需要先突破外层类才能访问内部类:dbd8ffb87beb4dfaae77a4c605c1832a.png

注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名:ff5c02b140e64a539e6e603487d2b130.png

 我们用同一道题来对比一下外部类和内部类:

求1+2+3+...+n_牛客题霸_牛客网 (nowcoder.com)

7d7be28b83b64f04a064c17913fac36d.png

假设我们调用一次FUN函数就会调用一次拷贝构造,因为调用就要传参,传参就要拷贝构造:3057a410109245ee86e57b266afc4662.png假设我们用Fun函数再调用一个打印函数:bb6042bb2dc44df999e83aa73c046dd6.png

 print函数只用打印就可以了,所以我们无需传参,也就不需要再调用一次拷贝构造函数了,所以我们用引用:64d0ba62d3844d458dd31dbb835175c3.png

660a28ae3d0248c788a2c133a343e118.png

 为了防止被更改,我们给引用加一个const修饰一下:=91834a8886794de9a7ef3169087eccf4.png 这是const对象不能修饰非const对象,这是权限的放大,所以我们给print函数也加个const缩小一下权限,这样Fun函数就可以修饰了:bbc5149b8b774e88a35bbc8e07a5e93e.png

Fun(A())是匿名对象,会调用构造函数,出了当前行就结束:

d3b97baf810e431f8c81f0d1950b1a9a.pngconst引用会延长匿名对象的结束周期:d83a563cd17a4b1887c149ad0ba2eca8.png

编译器的自动优化:

如图,调了三次函数,传了三次参,却只调了一次拷贝构造,这是编译器的优化:编译器认为频繁的调用拷贝构造太麻烦了:

例1:a2a1c362cdd8443b9c795828f8f8c535.png例2:7e51685aa6c041fcb3f7903156cf7608.png例3:c6215f0df8dc4c35a437632fdc86ee4b.png

内存管理

当我们不写析构函数的时候,下面程序中编号为1,2,3的三条语句的运行结果分别为:


class A
{
public:
	A()
	{
		cout << "调用一次析构" << endl;

	}
	//~A()
	//{
		cout << "调用一次析构" << endl;
//
	//}
private:
	int _a;
};

int main()
{
	A* p2 = new A[10];

	free(p2);    //1
	//delete p2;  //2
	//delete[]p2;   //3


	return 0;
}

 当我们写了析构函数后下面程序的运行结果分别为:


class A
{
public:
	A()
	{
		cout << "调用一次析构" << endl;

	}
	~A()
	{
		cout << "调用一次析构" << endl;

	}
private:
	int _a;
};

int main()
{
	A* p2 = new A[10];

	free(p2);    //1
	//delete p2;  //2
	//delete[]p2;   //3


	return 0;
}

我们发现只有delete[ ]p2成功跑起来了,并且调用了十次析构。

解析:

当写了析构时:

 为什么free(p2)和delete p2不行:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孙鹏宇.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值