一、构造函数
- 特殊的成员函数
- 定义类的对象时,系统自动调用构造函数来创建并初始化对象
- 与普通函数定义方式相同
- 实现:类内√ 类外√
特点
- 函数名必须与类名相同
- 无返回值类型
- 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;
}
一定要记得最后要释放申请的动态内存空间