一、构造函数
- 特殊的成员函数
- 定义类的对象时,系统自动调用构造函数来创建并初始化对象
- 与普通函数定义方式相同
- 实现:类内√ 类外√
特点
- 函数名必须与类名相同
- 无返回值类型
- public属性
- 只在创建对象时由系统自动调用
代码实例
#include <iostream> using namespace std; class CDate { private: int Date_Year, Date_Month, Date_Day; public: CDate(int, int, int); void Display(); }; //在类外定义构造函数 CDate::CDate(int year, int month, int day) { cout << "Constructor called" << endl; Date_Year = year; Date_Month = month; Date_Day = day; } //在类外定义Display()函数 void CDate::Display() { cout << "Date: " << Date_Day << "/" << Date_Month << "/" << Date_Year << endl; } int main() { CDate today(2024,3,17); cout << "---------------------" << endl; today.Display(); return 0; }
系统默认的构造函数
- 类定义中没有定义构造函数,编译器自动生成默认的构造函数
- 无形参
- 无语句
- 仅用于创建对象,为对象分配空间
- 不初始化其中成员数据
- 如果类定义中已经为类提供了任意一种形式的构造函数,编译器不再提供默认无参构造函数
- 需要用户自己定义
- 一个类可以拥有多个构造函数(可重载)
具有默认参数值的构造函数
在定义构造函数时,为避免出现因参数数量不同而找不到合适的构造函数,建议构造函数采用带默认参数值的形式比较安全
初始化列表
- 初始化列表是初始化对象某些特殊数据成员的唯一方法
- 引用&const
- 注意
- 系统调用构造函数时,先执行初始化列表
- 成员间可以相互初始化
- 成员初始化的顺序只与声明顺序有关,与初始化顺序无关
代码实例
#include <iostream> using namespace std; class Circle { private: int radius; int &b=radius; const double pi=3.14; public: Circle(int r):radius(r) { radius=r; cout<<radius<<" "<<b<<" "<<pi<<endl; } void show() { cout<<"area="<<pi*radius*radius<<endl; } }; int main() { int aa=2; Circle c(aa); c.show(); return 0; }
注:在vs2010中,这段代码是会报错的;但在vscode(使用最新的的mingw)和vs2022(最新版)中都不会报错,且能正常运行
稍作修改
public: Circle(int r):radius(r),b(r),pi(3.14) { radius=r; cout<<radius<<" "<<b<<" "<<pi<<endl; }
就能正常运行。在老版本中,引用和const只能使用初始化列表来初始化
复制构造函数
- 同类对象的常引用
- 不定义复制构造函数,编译器会自动生成
- 系统自动调用的情况
- 新对象:由一个已定义的对象初始化一个新对象
- 传参:函数调用、对象作为实参传递给函数形参时
- 引用和指针不会调用
- 返回值:对象作为函数返回值
#include <iostream> using namespace std; class CDate { private: int Date_Year, Date_Month, Date_Day; public: CDate(int y=2019, int m=1, int d=1); CDate(const CDate& date); void Display(); }; CDate::CDate(int y, int m, int d): Date_Year(y), Date_Month(m), Date_Day(d) { cout << "Constructor called" << endl; } CDate::CDate(const CDate& date) { cout << "Copy constructor called" << endl; Date_Year = date.Date_Year; Date_Month = date.Date_Month; Date_Day = date.Date_Day+1; } void CDate::Display() { cout << Date_Year << "-" << Date_Month << "-" << Date_Day << endl; } CDate fun(CDate date) { CDate new_date(date); return new_date; } int main() { CDate date1(2020, 1, 1); //Constructor called cout<<endl; //换行 CDate date3 ; //Constructor called cout<<endl; //换行 CDate date2(date1); //copy_1 //Copy constructor called cout<<endl; //换行 CDate date4 = date1; //copy_2 //Copy constructor called cout<<endl; //换行 date3 = date2; //没有输出 cout<<endl; //换行 date3 = fun(date2); //3次Copy constructor called cout<<endl; //换行 date3.Display(); //Copy constructor called cout<<endl; //换行 return 0; }
注:在vscode中会出现一共只有4次 Copy constructor called 的情况,这是因为在 return newdate2 中不调用复制构造函数
但是在 vs2010 中是调用的
析构函数
- 对象生命周期结束时,需要释放所占用的内存资源
- 说明
- 实现可以在类内,也可在类外
- 函数名与类名相同,前面加“~”
- 公有,无返回值类型
- 无形参,不能被重载,有且仅有一个
- 析构函数调用
- 对象生命周期结束,系统自动调用
- new动态创建的对象,用delete释放申请的内存
- 析构函数的调用顺序永远与构造函数的调用顺序相反
代码实例
#include <iostream> using namespace std; class CDate { private: int Date_Year, Date_Month, Date_Day; public: CDate(int year=2021, int month=1, int day=1); ~CDate(); }; CDate::CDate(int year, int month, int day) : Date_Year(year), Date_Month(month), Date_Day(day) { cout<<"Constructor:"<<Date_Year<<"-"<<Date_Month<<"-"<<Date_Day<<endl; } CDate::~CDate() { cout<<"Destructor:"<<Date_Year<<"-"<<Date_Month<<"-"<<Date_Day<<endl; } int main() { CDate today; CDate tomorrow(2022, 1, 1); return 0; }
析构函数与动态内存分配
#include <iostream> #include <cstring> using namespace std; class CMessage { private: char *pmessage; //指向消息的指针 public: CMessage (const char *text="中国一点都不能少") { pmessage = new char[strlen(text)+1]; //申请动态空间 strcpy_s(pmessage, strlen(text)+1, text); //拷贝字符串到内存中 } void show() { cout << pmessage << endl; } ~CMessage() { cout<<"Destructor called"<<endl; delete[] pmessage; //释放动态空间 } }; int main() { CMessage message1; CMessage message2("Hello World!"); CMessage *p = new CMessage("C++ is awesome!"); message1.show(); message2.show(); p->show(); delete p; return 0; }
一定要记得最后要释放申请的动态内存空间