类和对象(下)

目录

内部类

内部类的特性

匿名对象

拷贝对象时的优化

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

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

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

内存管理

[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型的数据通过直接构造 形成一个临时变量 ,在拷贝构造 将值拷贝给开辟的空间,而编译器为提高效率直接优化为一次直接构造

相关推荐
SteveDraw1 小时前
C++动态链接库封装,供C#/C++ 等编程语言使用——C++动态链接库概述(总)
开发语言·c++·c#·封装·动态链接库
十五年专注C++开发1 小时前
设计模式之单例模式(二): 心得体会
开发语言·c++·单例模式·设计模式
?!7141 小时前
算法打卡第18天
c++·算法
zh_xuan1 小时前
c++ std::pair
开发语言·c++
CodeWithMe2 小时前
【C/C++】EBO空基类优化介绍
开发语言·c++
k要开心2 小时前
从C到C++语法过度1
开发语言·c++
whoarethenext2 小时前
使用 C/C++的OpenCV 实时播放火柴人爱心舞蹈动画
c语言·c++·opencv
能工智人小辰3 小时前
Codeforces Round 509 (Div. 2) C. Coffee Break
c语言·c++·算法
梦星辰.3 小时前
VSCode CUDA C++进行Linux远程开发
linux·c++·vscode
whoarethenext3 小时前
C++ OpenCV 学习路线图
c++·opencv·学习