类与对象\构造函数与析构函数

一、构造函数

  • 特殊的成员函数
  • 定义类的对象时,系统自动调用构造函数来创建并初始化对象
  • 与普通函数定义方式相同
    • 实现:类内√        类外√

特点

  • 函数名必须与类名相同
  • 无返回值类型
  • 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;
}

一定要记得最后要释放申请的动态内存空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tsglz3210

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值