对象的初始化:
对象在创建时获得了一个特定的值,我们说这个对象被初始化。初始化不是赋值,初始化的含义是创建变量赋
予其一个初始值,而赋值的含义是把当前值擦除,而以一个新值来替代。
默认初始化:
如果定义变量时没有指定初值,则变量被默认初始化,此时变量被赋予了“默认值”
1、如果是内置类型的变量且未被显示初始化,它的值由位置决定。定义在任何函数体之外的变量被初始化
为0.定义在函数体内部的内置类型变量将不被初始化(当然如果是static类型,则执行值初始化,内置类型
的静态变量初始化为0);
2、每个类各自决定其初始化对象的方式。而且是否允许不经过初始化就定义对象也由类自己决定;
拷贝初始化:
(只能提供一个初始值)如果使用一个等号初始化一个变量,实际上执行的是拷贝初始化
编译器会把等号右侧的初始值拷贝到新创建的对象中去
int a = 0;
int a = {0};
string str1 = "hello";
直接初始化:
如果不使用等号,则执行的是直接初始化
int a(0);
int a{0};
string str1("hello");
string str2(10, 'c');//这种情况拷贝初始化不能完成
类内初始化:
为类内数据成员提供一个类内初始值
1、类内初始值用于初始化数据成员。没有初始值的成员被默认初始化
限制:类内初始值只能放在花括号里,或放在等号右边,记住不能使用圆括号
列表初始化:{}
1、当用于内置类型的变量时,如果我们使用列表初始化且初始值存在丢失的风险,则编译器报错
long double ld = 3.1415926;
int a{ld}, b = {ld};//错误:转换未执行,因为存在丢失信息的风险
2、如果提供的是初始化元素值得列表,则只能把初始值都放在花括号里进行列表初始化,而不能放在
圆括号里。
拷贝初始化构造函数的功能就是用一个已知的对象来初始化另一个对象。在下述三种情况下,需要用拷贝初始化构造函数来用一个对象初始化另一个对象。
1、明确表示由一个对象初始化另一个对象时,如:TPoint P2(P1);
2、当对象作为函数实参传递给函数形参时,如:上例 P = f(N);
3、当对象用为函数返回值时,
对象的销毁
一般而言,需要销毁的对象都应该做清理,为每个类都提供一个public的free函数,对象不再需要时立即调用free函数进行清理,
class Test
{
private:
int* p;
public:
Test()
{
p = new int
};
void free()
{
delete p
};
};
ree 只是一个普通的函数,必须显示的调用
对象销毁前没有做清理,很可能造成资源浪费
析构函数是对象销毁时进行清理的特殊函数,析构函数在对象销毁时自动被调用,析构函数是对象释放系统资源的保障。
对象的复制和移动
对象的复制是在对象声明时进行的操作,而赋值是在声明之后的操作。一般而言,复制的语法为A a(b),A为类,b为已经定义的对象,a为复制b的对象;。
有一种特殊的情况,A a=b;虽然是使用了操作符=,但由于是在对象声明时,进行定义,所以依然调用复制方法。
一般形式 :
类名 对象2(对象1);
类名 对象2=对象1;
下面代码为对象的复制操作:
#include<bits/stdc++.h>
using namespace std;
class Student
{
string m_strName;
public:
Student()
{
m_strName="Jim";
}
/*
默认的拷贝构造函数:
Student(const Student &stu){}
*/
Student(const Student &stu)
{
m_strName=stu.m_strName;
}
//显性定义的拷贝构造函数
};
int main()
{
Student stu1;
Student stu2=stu1;
Student stu3(stu1);
return 0;
}
对象的移动:
右值引用:必须绑定到右值的引用,右值引用只能绑定到一个将要销毁的对象上。
左值表达式表示一个对象,右值表达式表示一个对象的值
左值表达式:返回左值引用的函数、连同赋值、下标、解引用、前++/–
右值表达式:连同算术、关系、位、后++/–运算
右值引用的所有对象将会被销毁,该对象没有其它用户
移动构造函数和移动赋值运算符
这两个函数的参数必须是一个右值引用
必须保证移后的源对象销毁它无害(指针成员指向nullptr)
移动构造函数不分配任何新内存,接管被移动对象中的内存。
合成移动操作函数被隐式定义为=delete的情况
1.移动操作函数被定义为=default,但又不能移动所有成员
2.类中某个成员不能被移动。