目录
4.赋值运算符重载(已经构造好)--也是拷贝行为,但是不一样的是,拷贝构造是构造一个对象时,拿同类的对象初始化的拷贝
1.构造函数--初始化,大部分时候需要我们自己写
特性:
- 函数名和类名相同
- 无返回值
- 对象实例化时编译器自动调用对应的构造函数
- 构造函数支持重载
实现:
默认构造函数(不用参数就可以调用)有3种:全缺省最实用;同时只能存在一个
我们不写,编译器自己生成的,初始化自定义类型,内置类型不管;d1
自己写的无参的;d2
自己写的全缺省的;d3
#include<iostream>
using namespace std;
class Date
{
public:
Date()//无参
{
_year = 2022;
_month = 9;
_day = 12;
}
Date(int year = 2022,int month = 9,int day = 13)//全缺省的
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int* _a;
int _size;
int _capacity;
};
int main()
{
Date d1;
d1.Print();
Date d2;
d1.Print();
Date d3(2022,2,3);
d1.Print();
return 0;
}
编译器生成的构造有什么作用
编译器生成的构造函数是有偏见的,对内置类型不做任何处理,而对自定义类型进行处理(调用其构造函数)
#include<iostream>
using namespace std;
class Student
{
public:
Student(int num = 20220912,int age = 13,double weight = 50)
{
_num = num;
_age = age;
_weight = 60;
cout << "num:" << num << endl << "age:" << age << endl << "weight:" << weight << endl;
}
private:
int _num;
int _age;
double _weight;
};
//日期函数中没有构造函数
class Date
{
public:
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
Student _s;//成员变量里面有一个自定义类型
};
int main()
{
Date d1;
d1.Print();
return 0;
}
2.析构函数--清理对象中的资源
特性:
- 析构函数名是在类名前加上字符~
- 无参数无返回值
- 一个类只有一个析构函数,若未显示定义,系统会自动生成默认的析构函数
- 对象生命周期结束时,c++编译系统自动调用析构函数;
实现:
一般都不用我们写,一般只有malloc动态开辟空间才需要析构函数
#include<iostream>
using namespace std;
class Stack
{
public:
Stack(int capacity = 4)
{
if (capacity == 0)
{
_a = nullptr;
_size = _capacity = 0;
}
else
{
_a = (int*)malloc(sizeof(capacity));
_size = _capacity = capacity;
}
}
~Stack()
{
cout << "~Stack" << endl;//看是否执行了析构
free(_a);
_size = _capacity = 0;
_a = nullptr;
}
private:
int* _a;
int _size;
int _capacity;
};
int main()
{
Stack s1;
return 0;
}
看是否调用了析构;
编译器生成的析构有什么作用
类似于默认生成的构造函数一样,对内存类型不作任何处理,但是对自定义类型(会调用其析构函数)。
默认生成的析构函数基本上也不做什么事情,release下优化,就没了
3.拷贝构造函数--拷贝初始化,特殊构造函数 深浅拷贝问题
特性:
- 拷贝构造函数是构造函数的一个重载类型
- 拷贝构造函数的参数是有一个且必须使用引用传参,使用传值传参会引发无穷的递归调用
实现:
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 2022,int month = 9,int day = 13)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
Date(Date& d)//
{
_year = d._year;
this->_month = d._month;
this->_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 2, 4);
cout << "d1:" ;
d1.Print();
Date d2(d1);
cout << "d2:";
d2.Print();
return 0;
}
为什么拷贝构造一定要使用引用传参,不能使用传值传参、
如果把d1传值传给Date d;自定义类型可以直接拷贝吗?不可以需要拷贝构造来拷贝复制,所以就死循环了,引用就是我是他的别名
编译器生成的拷贝构造有什么作用
- 默认生成的就够用了,不需要我们写;
- 对内置类型(
int
,double
,char
等),会完成其值拷贝(浅拷贝) - 对自定义类型,会调用自定义类型的拷贝构造函数
4.赋值运算符重载(已经构造好)--也是拷贝行为,但是不一样的是,拷贝构造是构造一个对象时,拿同类的对象初始化的拷贝
特性:
- 函数名operator=
- 返回值Date&
- 返回*this
- 检测是否为自己复制this!=&d
实现:
不要我们写
#include<iostream>
using namespace std;
class Date
{
public:
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
Date& operator=(Date& d)//赋值运算符重载
{
if(this!=&d)
{
_year = d._year;
this->_month = d._month;
this->_day = d._day;
return *this;
}
return *this;
}
private:
int _year;
int _month;
int _day;
Stack _s1;
};
int main()
{
Date d1(2022, 2, 4);
cout << "d1:" ;
d1.Print();
Date d2;
d2 = d1;
cout << "d2:";
d2.Print();
return 0;
}
编译器生成的拷贝构造有什么作用
- 默认生成的就够用了,不需要我们写;
- 对内置类型(
int
,double
,char
等),会完成其值拷贝(浅拷贝) - 对自定义类型,会调用自定义类型的拷贝构造函数
总结:
- 构造和析构的特性是类似的,我们不写编译器会自动生成一个,内置类型不处理,自定义类型会调用它的构造和析构
- 拷贝构造和赋值运算符重载是类似的,内置类型会完成浅拷贝,自定义类型会调用他们的拷贝构造和赋值重载
剩下2个(没啥用)
Date* operator&()
{
return *this;
//return nullptr;
}
const Date* operator&()const
{
return this;
//return nullptr;
}
- 都是取我自己的地址,没啥用
- 为啥是两个,他们构成重载
- 唯一的作用可以不让别人访问我的地址