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