类的六个默认函数(构造,析构,拷贝等)

mac2024-04-06  35

目录

1.构造函数1.1概念1.2构造函数的特性1.3初始化列表1.4关于构造函数你还需要知道 2.拷贝构造函数2.1概念2.2拷贝构造函数的特性 3.析构函数3.1概念3.2析构函数的特性 4.运算符重载4.1赋值运算符重载4.2运算符重载 5.const 修饰的成员函数5.1概念 6.取地址和const取地址操作符重载

1.构造函数

1.1概念

构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个成员变量都有一个合适的初始值,并在对象的生命周期只调用一次。

class Date { public: Date(int year = 1900, int month = 1, int day = 1) //带默认参数的构造函数 { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; };

注:构造函数只是完成初始化的工作,不会负责给对象开辟空间

Date *p=new Date(2020,11,24) //new:完成给对象开辟空间 //构造函数:完成对象的初始化

1.2构造函数的特性

名字必须与类名相同没有返回值类型在创建对象时,编译器自动调用,并且在对象的声明周期内只调用一次构造函数可以重载如果没有显示给出构造函数,则编译器会默认生成一份无参的构造函数无参构造,全缺省构造,编译器生成的都叫默认构造函数,他们不能共存具有初始化列表成员的初始化顺序与成员在类中的声明顺序有关(避免,成员初始化成员)

1.3初始化列表

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初值。 但是,不能将其称为类对象成员的初始化,构造函数中的语句只能称其为赋初值,因为**初始化只能有一次,**而构造函数可以多次赋初值。 以一个冒号开始,接着以一个逗号分隔的数据成员列表,每个成员变量后面根一个放在括号里面的初始值或表达式。

class Date { public: Date(int year, int month, int day) : _year(year) , _month(month) , _day(day) {} //Date(){} //无参构造 private: int _year; int _month; int _day; };

注:

1.尽量使用初始化列表,自定义类型的成员变量一定会先使用初始化列表进行初始化 2.每个成员在初始化列表中只能出现一次(初始化只能进行一次) 3.成员变量的初始化与他们定义的顺序有关,和构造函数初始化列表中的先后顺序无关 3.类中包含以下成员,必须放在初始化列表位置进行初始化: 引用成员变量 、const成员变量 、类类型成员(该类没有默认构造函数) 4初始化列表用户可以不显示给出,但是不给出并不代表没有初始化列表,编译器会自动补全,只是补全时给成员变量中 放置的是随机值

1.4关于构造函数你还需要知道

构造函数不能被const修饰,const修饰成员函数本质上是修饰this指针,(const Date* const this ),this指针指向的变量中的内容不能改变,有些成员变量需要经过计算才能赋值构造函数不能是静态成员函数,静态成员函数只能对静态数据操作,构造函数主要针对非静态成员初始化,矛盾构造函数不能是虚函数,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。

2.拷贝构造函数

2.1概念

只有单个形参,该形参是对本类类型对象的引用(一般用const修饰)在用已存在的类对象创建新对象时由编译器自动调用

Date(const Date& d) { _year = d._year; _month = d._month; _day = d._day; }

2.2拷贝构造函数的特性

拷贝构造函数是一种特殊的构造函数,可以看做是构造函数的一种重载形式参数必须是类类型对象的引用(传值会造成死递归,传值的方式,形参就是实参的一份临时拷贝,生成临时对象又要调用拷贝构造)若未显示定义,编辑器会默认生成。如果类对象涉及资源管理,则一定要显示给出拷贝构造函数,因为编译器默认的拷贝构造函数是一种浅拷贝的方式,导致多个对象共用一份资源,销毁时就会引起代码崩溃。

3.析构函数

3.1概念

在对象进行销毁时,由编译器自动调用,完成对象中资源的清理。(注:不负责回收空间)

typedef int DataType; class SeqList { public: SeqList(int capacity = 10) { _pData = (DataType*)malloc(capacity * sizeof(DataType)); assert(_pData); _size = 0; _capacity = capacity; } ~SeqList() { if (_pData) { free(_pData); // 释放堆上的空间 _pData = NULL; // 将指针置为空 _capacity = 0; _size = 0; } } private: int* _pData; size_t _size; size_t _capacity; };

3.2析构函数的特性

名字是在构造函数名字前加 ~没有返回值类型没有参数(不能重载)在对象销毁时,编译器自动调用,完成对象中资源清理的工作用户没有显示定义,编译器会默认生成若对象中没有涉及到资源管理时,析构函数是否给出无所谓

4.运算符重载

4.1赋值运算符重载

为了增强代码的可读性引入运算符重载。两个已经存在的对象之间的赋值运算。

Date& operator=(const Date& d) { if(this != &d) { _year = d._year; _month = d._month; _day = d._day; } return *this; }

赋值运算符主要有四点:

1.参数类型 (类类型对象的引用) 2. 检测是否自己给自己赋值 3. 返回值,返回*this 4. 一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝。

4.2运算符重载

函数名字为:关键字operator后面接需要重载的运算符符号。 函数原型:返回值类型 operator操作符(参数列表)

// 左操作数是this指向的调用函数的对象 //bool operator=(Date* this, const Date& d2) bool operator=(const Date& d2) { return _year == d2._year && _month == d2._month && _day == d2._day; }

不能重载的运算符只有5个:

. (成员访问运算符) .* (成员指针访问运算符) :: (域运算符) sizeof (长度运算符) ?: (条件运算符)

注意:

不能引入新的自定义的运算符进行重载运算符重载时必须符合该运算符的含义如果该运算符重载为类的成员函数时,形参个数少一个(隐藏的this指针)为了区别后置++和前置++,给后置++多加了一个int型参数,在调用时int型的参数不用传递(同理–)

5.const 修饰的成员函数

5.1概念

将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。(除了被mutable修饰的成员变量) 注:mutable修饰类的成员变量,被mutable修饰的成员变量可以在const成员函数中修改

void Display() const//const修饰的成员函数 { cout << "Display () const" << endl; cout << "year:" << _year << endl; cout << "month:" << _month << endl; cout << "day:" << _day << endl << endl; }

补充:

const对象可以调用其他const函数,传入的this指针是const T*this非const对象可以调用非const成员函数和const 成员函数 const成员函数只能调用其他const成员函数非const成员函数可以调用其他const成员函数和非const 成员函数

6.取地址和const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

Date* operator&() { return this; } const Date* operator&()const { return this; }

代码如下:

class Date { public: //this指针:类类型* const,指向当前调用函数对象的指针 //谁调用指向谁,作为成员函数的第一个参数,只存在于成员函数中。 void Setdate(int year, int month, int day) { this->_year = year; _month = month; _day = day; } Date(int year = 1900, int month = 1, int day = 1)//构造函数 { _year = year; _month = month; _day = day; } Date(const Date& d)//拷贝构造函数 { _year = d._year; _month = d._month; _day = d._day; } void Display() const//const修饰的成员函数 { cout << "Display () const" << endl; cout << "year:" << _year << endl; cout << "month:" << _month << endl; cout << "day:" << _day << endl << endl; } ~Date()//析构函数 { cout << "~Date()" << endl; } bool operator==(const Date& d2)//运算符重载 { return _year == d2._year && _month == d2._month && _day == d2._day; } Date& operator=(const Date& d)//赋值运算符重载 { if(this != &d) { _year = d._year; _month = d._month; _day = d._day; } return *this; } //取地址及const取地址操作符重载 Date* operator&() { return this; } const Date* operator&()const { return this; } void diaplsy() { cout << "Display () const" << endl; cout << "year:" << _year << endl; cout << "month:" << _month << endl; cout << "day:" << _day << endl << endl; } private: int _year; int _month; int _day; };
最新回复(0)