😀人生的成功,不在于拿到一幅好牌,而是怎样将坏牌打好。你缺少的不是金钱,而是能力,经验和机会。所有的抱怨,不过是逃避责任的借口。一起加油!!
目录
构造于析构
构造函数(重要)
构造函数,在创建对象时系统会自动调用的函数;结构于成员函数类似 没有返回值
析构函数的名 = 类名 构造函数可以带参数(有参构造);构造函数必须是公共类型。
class Data{
Data() //无参构造函数
{};
};
构造分类
构造函数分为无参构造和有参构造(赋值和拷贝) 有参构造一般用于做初始化工作
class Data
{
private:
int m_A;
int m_B;
public:
//构造函数可以重载
Data()
{
cout<<"无参构造"<<endl;
}
Data(int a)
{
m_A = a;
cout<<"一个参数构造函数"<<endl;
}
Data(int a,int b)
{
m_A = a;
m_B = b;
cout<<"两个参数构造函数"<<endl;
}
};
void test_01()
{
Data d1; //隐式调用--推荐 无参构造
Data db1 = Data(); //显示调用
Data d2(10); //一个参数构造函数 --推荐
Data db2 = Data(10); //显示调用
Data d3(10,20); //两个参数构造函数
}
注意:当我们不写构造函数时,系统会自动产生无参构造函数 当自定义了构造函数后 系统将不会自动产生无参构造函数
析构函数(重点)
写法:由~和类名组成;析构函数不能带参数 所以析构函数没有重载; 比无参构造只多了~
调用了析构函数意味着我们要释放资源了
当我们不写构造函数 系统会自动生成
场景:我们在类成员中开辟了堆区空间需要释放 我们才必须要写析构函数
class Data
{
private:
int m_A;
int m_B;
public:
//构造函数可以重载
Data()
{
cout<<m_A<<"无参构造"<<endl;
}
Data(int a)
{
m_A = a;
cout<<m_A<<"一个参数构造函数"<<endl;
}
Data(int a,int b)
{
m_A = a;
m_B = b;
cout<<m_A<<"两个参数构造函数"<<endl;
}
~Data()
{
cout<<m_A<<"析构函数"<<endl;
}
};
void test_01()
{
Data d1; //隐式调用--推荐 无参构造
Data db1 = Data(); //显示调用
Data d2(10); //一个参数构造函数 --推荐
Data db2 = Data(11); //显示调用
Data d3(12,13); //两个参数构造函数
}
注意:析构函数和构造函数执行顺序相反。
拷贝构造函数(重要)
拷贝构造函数: 有参构造的一种
注意:如果用户不提供拷贝构造 编译器会提供一个默认构造函数(浅拷贝).
应用场景:只有类指针成员变量在堆区中开辟空间时 才有必要实现拷贝构造(深拷贝)
class Data
{
private:
int m_A;
public:
//构造函数可以重载
Data()
{
cout<<"无参构造"<<endl;
}
Data(int a)
{
m_A = a;
cout<<m_A<<"有参构造函数"<<endl;
}
~Data()
{
cout<<"析构函数"<<endl;
}
};
void test_01()
{
Data d1(10);
Data d2 = d1; //调用了系统拷贝构造函数
}
拷贝构造应用场景
类成员开辟空间 系统默认拷贝构造函数为浅拷贝 不会重新开辟空间 使用析构函数释放时 会出现重复释放(访问系统空间) 所以需要我们自定义拷贝构造函数 实现深拷贝
class Person
{
private:
char *m_Name;
int m_Age;
public:
Person()
{
cout<<"无参构造"<<endl;
}
Person(char *name,int age)
{
m_Name = (char*)malloc(strlen(name)+1);
strcpy(m_Name,name);
m_Age = age;
cout<<"有参构造"<<endl;
}
Person(const Person &p) //深拷贝 开辟新的空间
{
m_Age = p.m_Age;
m_Name = (char*)malloc(strlen(p.m_Name)+1);
strcpy(m_Name,m_Name);
cout<<"拷贝构造"<<endl;
}
~Person()
{
if(m_Name != NULL)
{
free(m_Name);
m_Name = NULL;
}
cout<<"析构函数"<<endl;
}
};
void test_01()
{
Person p1("zangsan",18); //有参构造
Person p2(p1); //拷贝构造
}
当类属性需要开辟空间时 就需要自定义拷贝函数 并使用析构函数释放空间
初始化列表(重要)
前面学习了带参构造函数 给成员属性赋值 初始化列表也是类似 给成员属性赋值
区别:初始化列表可以给当前类属性赋值 以及对象成员赋值 (以及父类成员赋值)
基本初始化列表
类名(形参):类成员(形参)
class A
{
public:
int m_A;
int m_B;
A(int a,int b):m_A(a),m_B(b) //初始化列表
{} //格式 构造函数: 函数名(形参a,形参b):类属性1(形参a),类属性2(形参b)
};
void test_01()
{
A a(10,20);
cout<<a.m_A<<" "<<a.m_B<<endl; //10 20
}
对象成员初始化列表
对象成员初始化列表
class B //类成员
{
public:
int m_C;
B(int c):m_C(c) //需要写有参构造 或 初始化列表
{}
};
class A
{
public:
int m_A;
int m_B;
B ob; //定义类成员
A(int a,int b,int c):m_A(a),m_B(b),ob(c) //ob(c)初始化列表初始化对象队成员
{}
};
void test_01()
{
A a(10,20,30);
cout<<a.m_A<<" "<<a.m_B<<" "<<a.ob.m_C<<endl; //10 20 30
}
explicit关键字(了解)
该关键字禁止使用隐式转换调用构造函数
class A
{
public:
int m_A;
explicit A(int a):m_A(a) //禁止隐式转换
{
cout<<"有参构造"<<endl;
}
};
void test_01()
{
//A a = 10; //ERROR explicit关键字禁止隐式转换调用构造函数
A a(10);
}
动态对象创建(new delete)
在C语言中提供了malloc函数对动态对象开辟空间 并使用free函数进行释放
然而这些函数在C++中不能很好的运行 因为它不能帮我们完成对象的初始化工作
主要问题:
程序必须确定对象的长度
malloc返回一个void指针 C++不允许将void赋值给其他任何指针,必须强转
在操作对象中 更需要使用new方式调用构造函数
结论:c的动态内存分配函数太复杂,容易令人混淆 是不可接受的 C++中我们推荐使用运算符new和delete来动态分配内存
new和delete
//C的动态内存方式
int *p1 = (int*)malloc(sizeof(int));
*p1 = 5;
//C++的动态内春方式
int *p2 = new int;
*p2 = 6;
//简化方式
int *p3 = new int(7);
cout<<*p1<<" "<<*p2<<" "<<*p3<<endl; //5 6 7
//释放空间
free(p1);
delete p2;
delete p3;
数组的创建
int *arr1 = new int[5];
cout<<arr1[0]<<" "<<arr1[1]<<endl; //随机值 因为没有初始化
delete []arr1; //释放空间 []arr1:数组
int *arr2 = new int[5]{1,2,3,4,5}; //直接初始化
cout<<arr2[0]<<" "<<arr2[1]<<endl;
delete []arr2; //释放空间
对象的创建
A *a1 = new A; //自动调用无参构造
delete a1; //delete才会调用析构函数
A *a2 = new A(10); //自动调用有参构造
delete a2;
对象数组的创建
class A
{
public:
int m_A;
A()
{
cout<<"无参构造"<<endl;
}
A(int a):m_A(a)
{
cout<<"有参构造"<<endl;
}
~A()
{
cout<<"析构函数"<<endl;
}
};
void test_01()
{
A *arr = new A[3]{A(10),A(20),A(30)};
//A *arr = new A[3]{10,20,30}; //也可以 使用隐式转换 但是不建议
for(int i=0;i<3;i++)
{
cout<<arr[i].m_A<<" "; //10 20 30
}
cout<<endl;
delete []arr;
}
new的拷贝构造
前面学习了使用malloc进行拷贝构造 在C++中 真正的拷贝构造场景应该是通过new来进行拷贝构造
class Person
{
private:
char *m_Name;
int m_Age;
public:
Person()
{
cout<<"无参构造"<<endl;
}
Person(char *name,int age)
{
m_Name = new char [strlen(name)+1];
strcpy(m_Name,name);
m_Age = age;
cout<<"有参构造"<<endl;
}
Person(Person &p)
{
m_Name = new char [strlen(p.m_Name)+1];
strcpy(m_Name,p.m_Name);
m_Age = p.m_Age;
cout<<"拷贝构造"<<endl;
}
~Person()
{
if(m_Name == NULL)
{
delete m_Name;
m_Name = NULL;
}
cout<<"析构函数"<<endl;
}
};
void test_01()
{
Person p1("zangsan",18); //带参构造
Person p2 = p1; //拷贝构造
}