C++梁哥笔记day6
类与对象
一、类的扩展
- 类的大小
成员函数不占用类的大小 成员函数在代码区
1 | class Data{ |
运行结果:
- 在类里声明成员函数 在类外定义
1 | class Data{ |
运行结果:
- 分文件实现类(类的定义在头文件,成员函数在cpp中实现)
data.h
1 |
|
data.cpp
1 |
|
main.cpp
1 |
|
运行结果:
二、对象的构造和析构
构造函数和析构函数,这两个函数将会被编译器自动调用,构造函数完成对象的初始化动作,析构函数在对象结束的时候完成清理工作。
注意:对象的初始化和清理工作是编译器强制我们要做的事情,即使你不提供初始化操作和清理操作,编译器也会给你增加默认的操作,只是这个默认的初始化操作不会做任何事情。(空的函数)
1. 构造函数和析构函数的概述
构造函数主要用于创建对象时为对象的成员属性赋值,构造函数由编译器自动调动,无需手动调用。析构函数主要用于对象销毁前系统自动调用,执行一些清理工作。
构造函数:实例化对象的时候系统自动调用。
析构函数:对象释放的时候系统自动调用。
2. 构造函数和析构函数的定义
构造函数的语法:构造函数函数名和类名相同,没有返回值,不能有void,但可以有参数,可以重载。 ClassName(){}
析构函数的语法:析构函数函数名是在类名前加"~"组成,没有返回值,不能有void,不能有参数,不能进行函数重载 ~ClassName(){}
1 | class Data1 |
运行结果:
3.构造函数的分类以及调用
- 构造函数的分类
- 按参数类型:分为无参构造函数和有参构造函数
- 按类型分类:普通构造函数和拷贝构造函数(复制构造函数)
- 构造函数的调用
- 无参构造的调用形式:
- 实例化对象时:
- 隐式调用:
Data d1;
- 显示调用:
Data d2 = Data();
- 隐式调用:
- 实例化对象时:
- 有参构造的调用形式:
- 实例化对象时:
- 隐式调用:
Data d3(10);
- 显示调用:
Data d4 = Data(20);
- 隐式转换的方式(针对于只有一个数据成员):
Data d5 = 30;//转化成Data d5(30)
(尽量不用) - 匿名对象(当前语句结束,匿名对象立即释放):
Data(50)
;
- 隐式调用:
- 实例化对象时:
千万不要以以下代码这种方式调用无参构造函数:
1 | int main(){ |
注意:在同一作用域中,构造和析构的顺序相反,即最先构造的最后析构(释放)
4.拷贝构造函数的调用
- 拷贝构造函数
1
2
3
4
5//拷贝构造函数
Data(const Data &d){
cout<<"拷贝构造函数"<<endl;
num = d.num;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27class Data
{
private:
int num;
public:
Data(){
num = 0;
cout<<"无参构造函数"<<endl;
}
Data(int n){
num = n;
cout<<"带参构造函数"<<endl;
}
~Data(){
cout<<"析构函数"<<endl;
}
//拷贝构造函数
Data(const Data &d){
cout<<"拷贝构造函数"<<endl;
}
int getNum(){
return num;
}
void setNum(int n){
num = n;
}
};
如果用户没有定义拷贝构造函数,系统会提供一个默认的拷贝构造函数,进行的赋值操作(浅拷贝)
1 | void test11(){ |
运行结果:
- 拷贝构造函数的调用形式
- 隐式调用拷贝构造函数:
Person bob(lucy);
- 显式调用拷贝构造函数:
Person bob = Person(lucy);
- 隐式转换调用:
Person bob = lucy;
(用的最多)
什么时候会调用拷贝构造函数:记住一句话,旧对象初始化为新对象,才会调用拷贝构造函数。
下面的代码就不会调用拷贝构造函数:只是赋值
1 | void test11(){ |
运行结果:
拷贝构造函数的注意事项:
不能调用拷贝构造函数去初始化匿名对象,也是就说以下代码不正确
1
2
3
4
5
6void test12(){
Data d1(10);//有参构造
//调用不了拷贝构造函数 错
Data(d1);//Data(d1) ==> Data d1;造成d1重定义
}对象作为函数的参数,如果实参与形参都是普通对象,那么会调用拷贝构造函数
1
2
3
4
5
6
7
8
9//函数的形参是在函数调用的时候开辟空间
//此处的ob 就会调用拷贝构造
void myPrintData(Data ob){//Data ob = ob1;
cout<<"num = "<<ob.num<<endl;
}
void test13(){
Data ob1(10);
myPrintData(ob1);
}函数返回局部对象,在qtcreate中会被编译器优化,从而调用不了拷贝构造函数
1
2
3
4
5
6
7
8Data returnData(){
Data ob1(10);//调用有参构造函数
return ob1;
}
void test14(){
Data ob2 = returnData();
//实际上是ob2指向了ob1的空间,ob2的引用等于ob1的引用,并没有调用拷贝构造函数
}