1. 类的6个默认成员函数
当一个类中什么都没有,编译器会帮类自动生成6个默认成员函数例如:
class Date
{
};
此篇文章主要围绕构造函数与析构函数进行讲解。
2. 构造函数
2.1 概念
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Date
{
private:
int _year;
int _month;
int _day;
public:
void Init(int year = 1,int month = 1 ,int day = 1)
{
this->_year = year;
this->_month = month;
this->_day = day;
cout << "今天是" << _year << "/" << _month << "/" << _day << endl;
}
};
int main()
{
Date d1;
d1.Init(2024, 3, 15);
return 0;
}
- 对于以上的Date类,每次实例化对象之后都要对对象调用Init()函数,比较繁琐,其实编译器就可以帮我们完成。
- 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。
2.2 特性
构造函数是特殊的成员函数,其定义语法上有以下几点:
- 构造函数函数名与类名相同;
- 无返回值;
- 构成重载;
- 对象实例化时编译器自动调用构造函数。
class Date
{
private:
int _year;
int _month;
int _day;
public:
//带参构造函数
Date(int year, int month = 1, int day = 1)
{
this->_year = year;
this->_month = month;
this->_day = day;
cout << "今天是" << _year << "/" << _month << "/" << _day << endl;
}
//无参构造函数
Date()
{
this->_year = 1;
this->_month = 1;
this->_day = 1;
cout << "今天是" << _year << "/" << _month << "/" << _day << endl;
}
};
int main()
{
Date d1;
Date d2(2024, 3, 15);
return 0;
}
- 如果你在类中没有给出构造函数,那么编译器将会自动给出构造函数,如果给了构造函数,编译器就不会生成:
class Date
{
private:
int _year;
int _month;
int _day;
public:
带参构造函数
//Date(int year, int month = 1, int day = 1)
//{
// this->_year = year;
// this->_month = month;
// this->_day = day;
// cout << "今天是" << _year << "/" << _month << "/" << _day << endl;
//}
无参构造函数
//Date()
//{
// this->_year = 1;
// this->_month = 1;
// this->_day = 1;
//}
void Print()
{
cout << "今天是" << _year << "/" << _month << "/" << _day << endl;
}
};
int main()
{
Date d1;
d1.Print();
//Date d2(2024, 3, 15);
return 0;
}
- 以下这种情况就是你写了一份构造函数,但是没有匹配的,编译器也不会帮你生成。
class Date
{
private:
int _year;
int _month;
int _day;
public:
//带参构造函数
Date(int year, int month = 1, int day = 1)
{
this->_year = year;
this->_month = month;
this->_day = day;
cout << "今天是" << _year << "/" << _month << "/" << _day << endl;
}
//无参构造函数
/*Date()
{
this->_year = 1;
this->_month = 1;
this->_day = 1;
}*/
/*void Print()
{
cout << "今天是" << _year << "/" << _month << "/" << _day << endl;
}*/
};
int main()
{
Date d1;
//d1.Print();
Date d2();
return 0;
}
- 如果你没有构造函数,编译器会帮你调用构造函数,在它本身的构造函数中,如果是内置类型,例如(int ,double, char,指针类型等),则编译器不会帮你初始化,如果不是内置类型,例如(struct,class定义自定义类型等),编译器会帮你调用它的构造函数,例如以下是两个栈实现队列的简单定义:
struct Stack
{
int* _a;
int _top;
int _capacity;
// 栈的构造函数
Stack()
{
_a = nullptr;
_capacity = 0;
_top = 0;
cout << "This is Stack struct" << endl;
}
void CheckCapacity()
{
if (_top == _capacity)
{
int newcapacity = _capacity == 0 ? 4 : _capacity * 2;
int* tmp = (int*)realloc(_a, sizeof(int) * newcapacity);
if (tmp == nullptr)
{
perror("realloc error!");
exit(-1);
}
_a = tmp;
_capacity = newcapacity;
}
}
void Push(int x)
{
CheckCapacity();
_a[_top++] = x;
}
void Pop()
{
assert(_top > 0);
_top--;
}
int Top()
{
return _a[_top - 1];
}
bool Empty()
{
return _top == 0;
}
void Print()
{
while (!Empty())
{
cout << _a[_top - 1] << endl;
Pop();
}
}
};
struct Queue
{
//此处没有Queue的构造函数
Stack st1;
Stack st2;
};
int main()
{
Queue q;
return 0;
}
- C++11规定可以在类中的声明中给缺省值,例如:
class Date
{
public:
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year = 1;
int _month = 1;
int _day = 1;
};
int main()
{
Date d1;
d1.Print();
return 0;
}
- 总的来说你可以根据是否需要构造函数来决定是否需要编写构造函数;
- 通常情况下都是需要你自己编写构造函数的;
- 特别注意在构造函数的时候虽然构成函数重载,但是切忌全缺省参数和无参数的构造同时出现,不然会发生编译错误。
2.3 构造函数总结
- 构造函数函数名与类名相同;
- 无返回值;
- 构成重载;
- 在对象实例化的时候自动调用构造函数;
- 如果自己没有编写构造函数那么编译器会帮你自动生成构造函数;
- 对于编译器生成的构造函数中,内置类型不会进行初始化,自定义类型会帮你自动调用他的构造函数;
- 如果自己编写了构造函数,那么编译器会根据函数名修饰调用属于他的构造函数;
- 无参的构造函数、全缺省构造参数、编译器自己生成的构造函数统称为默认构造函数;
- 通常情况下是需要构造函数的。
3. 析构函数
3.1 概念
- 析构函数与构造函数相反,对象是通过构造函数来的,相反对象就是通过析构函数没的。
- 但是对象的销毁不是析构本身完成的,这是编译器的任务,但是在销毁的同时会自动调用析构函数。
3.2 特性
- 函数名是在类名之前加上~;
- 无返回值无参数;
- 若未显示定义,则系统会生成默认的析构函数,一个类只能由一个析构函数,不构成重载;
- 对象生命周期结束,C++编译器会自动调用析构函数。
class Date
{
public:
Date(int year,int month,int day)
{
this->_day = day;
this->_month = month;
this->_year = year;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
~Date()
{
cout << this << endl;
cout << "~Date" << endl;
}
private:
int _year = 1;
int _month = 1;
int _day = 1;
};
void func()
{
Date d1(2024,3,15);
}
int main()
{
func();
return 0;
}
- 默认生成的析构函数跟构造函数类似
- 内置类型不做处理,自定义类型的成员去调用他的析构
struct Stack
{
int* _a;
int _top;
int _capacity;
Stack()
{
_a = nullptr;
_capacity = 0;
_top = 0;
cout << "This is Stack struct" << endl;
}
void CheckCapacity()
{
if (_top == _capacity)
{
int newcapacity = _capacity == 0 ? 4 : _capacity * 2;
int* tmp = (int*)realloc(_a, sizeof(int) * newcapacity);
if (tmp == nullptr)
{
perror("realloc error!");
exit(-1);
}
_a = tmp;
_capacity = newcapacity;
}
}
void Push(int x)
{
CheckCapacity();
_a[_top++] = x;
}
void Pop()
{
assert(_top > 0);
_top--;
}
int Top()
{
return _a[_top - 1];
}
bool Empty()
{
return _top == 0;
}
void Print()
{
while (!Empty())
{
cout << _a[_top - 1] << endl;
Pop();
}
}
~Stack()
{
if (this->_a != nullptr)
{
free(this->_a);
this->_a = nullptr;
}
this->_capacity = this->_top = 0;
cout << "this is Stack Destroy" << endl;
}
};
struct Queue
{
Stack st1;
Stack st2;
};
int main()
{
Queue q;
return 0;
}
在构造的时候是先构造st1,在构造st2,析构的时候是先析构st2,在析构st1,注意顺寻,栈要符合 LIFO。
3.3 析构函数总结
- 函数名是在类名之前加上~;
- 无返回值无参数;
- 若未显示定义,则系统会生成默认的析构函数,一个类只能由一个析构函数,不构成重载;
- 对象生命周期结束,C++编译器会自动调用析构函数;
- 默认生成的析构函数跟构造函数类似;
- 内置类型不做处理,自定义类型的成员去调用他的析构。