类和对象(下)

目录

内部类

内部类的特性

匿名对象

拷贝对象时的优化

直接构造+拷贝构造-->优化为直接构造

拷贝构造+拷贝构造-->优化为一次拷贝构造

构造和析构调用顺序的先后

内存管理

[new 和 delete](#new 和 delete)

基本语法


内部类

什么是内部类?

类中定义的类 就是内部类

class A
{
public:
	A()
	{
		cout << "A()" << endl;
		_a = 1;
	}
	class B//内部类
	{
	public:
		B()
		{
			cout << "B()" << endl;
		}

	private:
		int _b;
	};
private:
	int _a;
};

类A和类B是独立 的,是两个平行类 ,但B类在A的类域中

所以

	A::B b;//定义内部类时需要指明类域

内部类的特性

类B天生是A的友元 ,意思就是可以访问类A的成员及在类A中定义的静态成员变量和静态成员函数。

class A
{
public:
	A()
	{
		cout << "A()" << endl;
		_a = 1;
	}
	class B//内部类
	{
	public:
		B()
		{
			cout << "B()" << endl;
		}
		void Print(A& a)
		{
			cout << a._a << endl;//可以访问类A中的成员
		}
	private:
		int _b;
	};
private:
	int _a;
};

int main()
{
	A::B b;
	A a;
	b.Print(a);
	return 0;
}

匿名对象

什么是匿名对象?

对象实例化时,对象没有变量名

	//A是一个类名
    A(1);//匿名对象
	A a(1);//有名

匿名对象的特点

就是该对象的生命周期只在 定义匿名对象所在的那行代码上

匿名对象的应用

void f(const A& a)
{
	cout << a._a << endl;
}

int main()
{
	A a(1);
	f(a);//平常使用需要先创建一个对象
	f(A(1));//使用匿名对象
	return 0;
}

上面有一个函数的调用需要传一个对象过去,可以直接将匿名对象当实参

拷贝对象时的优化

直接构造+拷贝构造-->优化为直接构造

class A
{
public:
	A(const A& a)//拷贝构造
	{
		cout << "copy A()" << endl;
		_a = a._a;
	}
	A(int a)//直接构造
	{
		cout << "default A()" << endl;
		_a = a;
	}

public:
	int _a;
};

void f(const A a)//传值
{
	cout << a._a << endl;
}
int main()
{
	f(A(1));//存在隐式类型转换
    return 0;
}

如果没有编译器优化 的话,调用f函数时,匿名对象会调用直接构造构造 一个临时对象 ,该函数时传值调用 ,所以需要调用拷贝构造将临时对象拷贝给形参。

以上可以知道,创建的临时对象会有性能消耗,并且没有多大作用,那有没有更好的办法初始化形参呢?

编译器优化后 ,直接拿着创建匿名对象的值 ,直接调用形参的直接构造就可以了,这样就避免了开临时变量的性能的消耗了。

拷贝构造+拷贝构造-->优化为一次拷贝构造

class A
{
    //.......
};
void f(const A a)//传值
{
	cout << a._a << endl;
}
int main()
{
	A a(1);
	f(A(a));//存在隐式类型转换
	return 0;
}

优化的目的是提升效率 ,优化后,是直接拿着已实例化的a直接拷贝构造函数的形参 。

构造和析构调用顺序的先后

1.在同一块代码块中定义的对象,后定义的先析构

class A
{
public:
	A()
	{
		cout << "default A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
};

class B
{
public:
	B()
	{
		cout << "default B()" << endl;
	}
	~B()
	{
		cout << "~B()" << endl;
	}
};

int main()
{
	A a;
	B b;
	return 0;
}

2.全局对象的构造在main函数定义的对象构造之前调用,并且析构的调用在main函数中定义的对象之后。

C c;//全局
int main()
{
	A a;
	B b;
	return 0;
}

3.静态对象的析构函数的调用在全局之前,在局部之后

C c;
int main()
{
	static D d;//静态对象
	A a;
	B b;
	return 0;
}

内存管理

new 和 delete

new就跟malloc差不多,在stack(栈)上开辟一块空间,并放回开辟的空间的首地址。

delete跟free差不多,释放在stack(栈)上开辟的空间,但并不会将指针置为nullptr

基本语法

开辟存放一个数据的空间

new + 数据类型

delete+ 指向new开辟的空间的指针

	int* ret = new int;
	delete ret;

如何开辟和释放一块连续的空间呢?

	int* ret1 = new int[10];//开辟10个int的空间
	delete[] ret1;//释放开辟的那块连续的空间

注意:以上开辟的空间同malloc开辟出的空间一样都没有初始化

初始化

	int* ret = new int(1);//初始化一块空间
	cout << *ret << endl;
	delete ret;
	int* ret1 = new int[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};//初始化一块连续的空间
	for (int i = 0; i < 10; i++)
	{
		cout << ret1[i] << " ";
	}
	cout << endl;
	delete[] ret1;

new和delete初始化内置类型,就差不多是这样了。

new和delete最重要的是为内置类型开辟和释放空间

	A* ret = new A;
	delete ret;

    A* ret1 = (A*)malloc(sizeof(A));
	free(ret1);

用new为自定义类型开辟和释放空间时,会自动调用构造和析构函数

new开辟一块连续的自定义类型的空间

	A* ret = new A[2];
	delete []ret;

为几个自定义类型 开辟空间就调用几个构造函数同时delete是就调用几个析构函数

为开辟的自定义类型的初始化

	A* ret = new A(1);//也可以这样写A* ret = new A{1};//单参数构造函数
	B* ret1 = new B{ 1,2 };//多参数构造函数
	A* ret2 = new A[10]{ 1,2,3 };
	B* ret3 = new B[10]{ {1,2},{2,4} }

无论是单参数还是多参数的自定义的初始化,都涉及到了隐式类型转换 ,将int型的数据通过直接构造 形成一个临时变量 ,在拷贝构造 将值拷贝给开辟的空间,而编译器为提高效率直接优化为一次直接构造

相关推荐
咖啡里的茶i5 分钟前
C++之Swap类
开发语言·c++·算法
hcmonk1 小时前
【音视频】ffmpeg其他常用过滤器filter实现(6-4)
c++·ffmpeg·音视频
熬夜学编程的小王1 小时前
【C++篇】迈入新世界的大门——初识C++(上篇)
开发语言·c++
航行的土豆1 小时前
UE学习篇ContentExample解读-----------Blueprint_Mouse_Interaction
c++·学习·算法·游戏程序·虚幻引擎
心怀花木1 小时前
【C++】继承
c++·继承
六点半8883 小时前
【C++】vector 常用成员函数的模拟实现
开发语言·c++·算法
禁默8 小时前
C++之stack 和 queue
开发语言·数据结构·c++
qmx_078 小时前
MFC - 常用基础控件
c++·mfc
兵哥工控9 小时前
MFC单按钮启停实例
c++·mfc
zyx没烦恼9 小时前
【C++】STL详解之string类
开发语言·c++