目录
引入类class
例1
例2
构造函数
特征
1.函数名和类名相同
2.无返回值
3.对象实例化时编译器自动调用对应的构造函数
4.可重载
5.构造函数是为了初始化的,但是它只初始化自定义类型,对内置类型不初始化
实例化
析构函数
概念
特征
1.在类名前加上字符 ~
2.无参数无返回值
3.只能有一个析构函数,没有编译器自己生成一个
拷贝构造
特征
1.拷贝构造是也是构造函数
2.拷贝构造参数必须传引用(为什么)
传值传参(语法限制)
传引用传参
传指针传参 (普通的构造函数)
#include
using namespace std;
class Date
{
public:
//成员函数
void Init(int year = 2023, int month = 1, int day = 28)//定义
{
_year = year;
_month = month;
_day = day;
}
void func()
{
}
//成员变量
private:
int _year;//声明
int _month;
int _day;
};
int main()
{
Date* ptr = nullptr;
ptr->func();
(*ptr).func();
ptr->Init(2022,1,28);
return 0;
}
引入成员函数和成员变量
运行结果是第三个跑不了
成员函数在代码段上,这里创建出来的对象的大小是12Bit(如果成员变量没有,默认大小是1Bit)
我自己的理解:ptr是一个Date类型的指针,具有获得Date类型信息的能力,虽然是一个空指针,但是不影响调用代码段里这个类域里的public成员函数,那么为什么(*ptr)这里不会解引用呢?
看下汇编,编译器实际上什么也没干,我觉得它就是获得一个类,到这个类域里面去找成员函数,如果是成员函数 ,那么就在代码段里,但如果是成员变量,栈里没有就会报错,可以说是找不到对应的左值
这里有个问题,下面的_year来自哪里
void Init(int year = 2023, int month = 1, int day = 28)
{
_year = year;
_month = month;
_day = day;
}
和c是大差不差,也是是要传,不然怎么赋值,但是c++的类,编译器自己传了 Date* this
也就是编译器简化了我们的操作
前面可以写成是 this->_year = year;
实际操作应该如下:
int main()
{
Date d1;
d1.Init(2024, 1, 28);
//d1.Init(&d1, 2024, 1, 28);
return 0;
}
#include
using namespace std;
class Date
{
public:
//不写 编译器自己生成的也是默认构造
//只能有一个默认构造函数
//Date()//默认构造函数
//{
//}
//Date(Date* this, int year = 2023, int month = 1, int day = 28)
//定义
Date(int year = 2023, int month = 1, int day = 28)//全缺省也是默认构造 Date*this
{
this->_year = year;
_year = year;
_month = month;
_day = day;
}
private:
int _year;//声明
int _month;
int _day;
};
注意:构造函数不是开空间创建对象,而是初始化对象
默认构造函数有3个,
1.不写时编译器自己生成
2.无参的构造函数
3.全缺省的构造函数
但是只能存在一个
其实非常简单,默认可以理解成不能传参数的构造函数,构造函数又可以重载,如果有多个无参的编译器不知道调哪一个
我是这么理解的:自定义类型也是由多个内置类型组成的,(这个自定义类型有构造)
只不过在你新的类的成员变量里的自定义类型,调用的也是写过的东西(java里叫组成)
简单来说,为什么只初始化自定义类型,因为你写过了,不是说你不用写,如果你不写,对应的内置类型就是随机值,针对这个问题,C++11打了补丁,引入成员变量的缺省参数
顺序是先执行默认构造,在执行成员变量的缺省参数( 资料:成员变量的缺省参数(即初始化器)会在默认构造函数中执行,而不是在对象创建时另外执行。
来个有意思的
int main()
{
Date d1;
Date d2();
return 0;
}
发现编译器d2这一行居然不报错,但是实际上编译器没有任何操作
这行代码没有对应的指令
你看 Date(类型) d2 (函数名/对象) 最后的()是 无参数
编译器不知道是声明函数还是实例化对象,语法上可以,调用时有歧义
对象销毁时会自动调用,主要是为了释放开辟的堆空间,同一块区域析构两次会运行崩溃
~Date()
{
print();
}
就像这样 print()证明调用过,有malloc的free就行
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
什么时候要调用拷贝构造?用一个Date类型去初始化另一个Date类型时候
int main()
{
Date d1;
Date d2(d1);
Date d3 = d1;
return 0;
}
在C++里一共有3中传参方式,,,
Date(const Date d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
为什么一定要传引用传参?
首先,你不写,编译器是会自己生成一个拷贝构造,这个拷贝构造是浅拷贝(值拷贝),只是单纯的赋值,如果说是这样:
Stack st1;
Stack st2(st1);
那么他们指针会指向用一个地方,很明显全乱套了(在这种有指针的情况下)
之前说的:用一个Date类型去初始化另一个Date类型时候会调用拷贝构造
那么如果是传值传参,他就会去调用拷贝构造(这里就好比是Date d(d1) ),好 现在去调用拷贝构造,但是这个拷贝构造里的参数 是一个传值传参,他又要去调拷贝构造,所以无穷递归
Date(const Date* d)
{
this->_year = d->_year;
this->_month = d->_month;
this->_day = d->_day;
}
调用时要多加&(取地址)
Date d1;
Date d2(&d1);
Date d3 = &d1;
欢迎提出问题,指出错误