C++中的构造函数,拷贝构造函数,析构函数和赋值运算符重载

C++对象生命周期:构造、拷贝、析构与赋值运算符
本文详细介绍了C++中的构造函数、拷贝构造函数、析构函数和赋值运算符重载。构造函数用于对象初始化,无返回值且在对象创建时自动调用。拷贝构造函数处理对象的复制,常在值传递、返回值及初始化时使用。析构函数在对象生命周期结束时自动调用,负责清理工作。赋值运算符重载则增强了代码的可读性,但也需要注意避免滥用。

1.构造函数

类的数据成员不能在声明类时初始化,为了解决这个问题,C++提供了构造函数(constructor)来处理对象的初始化。
构造函数特点:
1->函数名和类名相同。
2->无返回值,没有类型。(实际返回当前对象的引用)
3->构造函数不需要用户调用,也不能被用户调用,只会在新的对象被创建时,由编译器自动调用,且在对象的生命周期内仅调用一次,以保证每个数据成员都有一个合适的初始值。
4->有初始化列表(可以不用,只有构造函数有初始化列表)。
5->构造函数可以重载,实参决定调用哪个构造函数。
6->如果没有显示定义,系统会提供一个默认的构造函数。
7->无参构造函数和带有缺省值的构造函数都被认为是缺省构造函数,而且缺省构造函数只能有一个。
8->构造函数不能用const和volatile来修饰。

eg:
#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>

using namespace std;

class Data
{
public:            //   类内定义构造函数
    Data()         //定义构造成员函数,函数名与类名相同
    {
        year = 0;  //利用构造函数对对象中的数据成员赋初值
        month = 0;
        day = 0;
    }
    void set_data();            //函数声明
    void show_data();
private:
    int year;       
    int month;
    int day;
};

void Data::set_data()
{
    cin >> year;
    cin >> month;
    cin >> day;
}

void Data::show_data()
{
    cout << year << ":" << month << ":" << day << endl;
}

int main()
{
    Data d1;
    d1.set_data();              //对d1的数据成员赋值
    d1.show_data();             //显示d1数据成员值
    Data d2;
    d2.show_data();             //显示d2数据成员值
    return 0;
}

这里写图片描述
构造函数在类内的定义,也可以在类外定义。
在类外定义:

class Data
{
public:            //   类内定义构造函数
    Data(); 
    void set_data();            //函数声明
    void show_data();
private:
    int year;       
    int month;
    int day;
};

Data :: Data()
{
    year = 0;
    month = 0;
    day = 0;
}

构造函数小结:

1->构造函数不能用const修饰的原因:构造函数的作用是初始化对象,如果用const修饰构造函数,之后不能对该对象重新赋值。
2->有两个类,A和B,B类中含有A类的对象,A中显式定义了构造函数,B中无构造函数,此时,系统会在B类中合成一个默认构造函数。
3->成员初始化列表只提供该类数据化成员的初始化,而在构造函数体内对数据成员设置值失忆个赋值操作。

2.拷贝构造函数

拷贝构造函数:

一种特殊的构造函数,只有一个形参,而且该形参是对本类类型对象的引用,这样的构造函数称为拷贝构造函数。
拷贝构造函数特征:
1、它是构造函数的重载。
2、只有一个参数。
3、由普通构造函数和赋值操作符共同实现。
4、它的参数必须使用同类型对象的引用传递。
5、如果没有显式定义,系统会自动合成一个默认的拷贝构造函数。默认的拷贝构造函数会依次拷贝类的数据成员完成初始化。
拷贝构造函数的使用:
在C++中,下面三种对象需要调用拷贝构造函数(有时也称“复制构造函数”):
1) 一个对象作为函数参数,以值传递的方式传入函数体;
2) 一个对象作为函数返回值,以值传递的方式从函数返回;
3) 一个对象用于给另外一个对象进行初始化(常称为赋值初始化)。
eg:

class Point
{
    public:
        Point(int xx,int yy){X=xx;Y=yy;}
        Point(const Point& p);
        int getX(){returnX;}
        int getY(){returnY;}
    private:
        intX,Y;
};
Point::Point(const Point& p)
{
    X=p.X;
    Y=p.Y;
    std::cout<<"拷贝构造函数调用"<<std::endl;
}

3.析构函数

析构函数:
析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
C++中的析构函数格式:

class <类名>
{
     public:
       ~<类名>();
};
<类名>::~<类名>()
{
    //函数体
};

eg:

#include <string.h>
#include <iostream>

using namespace std;

class stud
    private:        
        int num;
        char name[10];
        char sex;
    public:
        stud(int n,const char nam[],char s)
        {
            num = n;
            strcpy(name, nam);
            sex = s;
        }

        ~stud() //析构函数
        {
            cout<<"stud has been destructed!"<<endl;//通过输出提示告诉我们析构函数确实被调用了
        }

    void display()
    {
        cout<<"num:"<<num<<endl;
        cout<<"name:"<<name<<endl;
        cout<<"sex:"<<sex<<endl;
    }
};
int main()
{
    stud stud1(10010, "Wang-li", 'f'), stud2(10011, "Zhang-fun", 'm');
    stud1.display();//输出学生1的数据
    stud2.display();//输出学生2的数据
    return 0;
}

这里写图片描述
当主函数结束时调用析构函数,输出stud has been destructe!。

4.赋值预算符重载

重载操作符是具有特殊函数名的函数,关键字operator后面接需要定义的操作符符号。操作符重载也是一个函数,具有返回值和形参表。它的形参数目与操作符的操作数目相同,函数调用操作符可以接受任意数目的操作数。使用运算符重载可以提高代码的可读性。返回类型 operate 操作符(参数列表)。
eg:

class A
{
public:
    A()
    {}

    A(int id,char *t_name)
    {
        _id=id;
        name=new char[strlen(t_name)+1];
        strcpy(name,t_name);
    }

    A& operator =(A& a)  //注意:此处一定要返回对象的引用,否则返回后其值立即消失!
    {
         if(name!=NULL)
            delete name;
         this->_id=a._id;
         int len=strlen(a.name);
         name=new char[len+1];
         strcpy(name,a.name);
         return *this;
    }

    ~A()
    {
        cout<<"~destructor"<<endl;
        delete name;
    }

    int _id;
    char *name;
};

int main()
{
 A a(1,"helloworld");
 A b;
 b=a;
}

这里写图片描述
小结:
使用重载操作符,可以令程序更自然、更直观,而滥用操作符重载会使得类难以理解,在实践中很少发生明显的操作符重载滥用。但有些程序员会定义operator+来执行减法操作,当一个重载操作符不明确时,给操作符取一个名字更好,对于很少用的操作,使用命名函数通常比用操作符好,如果不是普通操作,没有必要为简洁而用操作符。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值