C++类的六个默认成员函数

类的六个默认成员函数:
1. 构造函数
2. 拷贝构造函数
3. 析构函数
4. 赋值运算符重载
5. 取址(&)运算符重载
6. const修饰的取址运算符重载

我们先定义一个空类:

class A
{
};

在经过编译器处理之后它就不在为空,编译器会自动加入一些默认的成员函数,即使在这些函数中什么也不做。编译器处理之后的类相当于:

class A
{
public:
    A(); //构造函数
    A(const A& a); //拷贝构造函数
    ~A(); //析构函数
    A& operator =(const A& a); //赋值运算符重载
    A* operator &(); //取址运算符重载
    const A* operator &() const; //取址运算符重载
};

注意:这些函数在我们没有显式给出时编译器会为我们自动合成。

1、构造函数

什么是构造函数

它是一个特殊的成员函数,函数名与类名相同,无返回值,在创建对象时由编译器自动调用,以保证每个对象都有一个合适的初始值。在该对象的整个生命周期内只被调用一次。

class Time
{
public:
    //构造函数
    Time(int hour = 0, int minute = 0, int second = 0)
        :_hour(hour)
        ,_minute(minute)
        ,_second(second)
    {
        doSomeThing...
    }

private:
    int _hour;
    int _minute;
    int _second;
};

初始化列表

用于对对象成员进行初始化,格式为在函数名和函数体之间,以一个冒号开始,后面跟着以逗号隔开的数据成员列表,在每个成员后接一个圆括号,括号中为初始化的内容。

数据成员初始化顺序

即使初始化列表中的成员顺序与定义顺序不同,初始化顺序实际也与数据成员定义的顺序一致。
构造函数初始化
我们注意到,编译器在底层处理初始化列表时,是根据成员的实际定义顺序来一一初始化的,即先给hour赋值,接着minute,最后second,我们尝试修改了数据成员在初始化列表中的顺序后,它在底层的处理顺序人没有变。
构造函数初始化2

系统默认合成的构造函数

默认构造函数使用与成员变量初始化相同的规则初始化成员,对于内置类型和复合类型的成员,如数组、指针,只对定义在全局定义作用于的对象初始化,对于局部作用域的内置和复合类型不作初始化。

关键字explicit

explicit(明确的)关键字可以阻止构造函数对类型的转换。
有时你可能会写出下面的代码(Time为上面的时间类)

Time t;
int a = 10;
t = a;

因为该对象的第一个成员也为int型,所以编译器会将这种代码视为正常,可实际上使用int型的变量给一个类类型的对象可能不是我们期望的做法。若果你这样做了,结果将如下:
T = a;
它将int型的变量赋给第一个成员,这在某些情况下会造成严重的后果。为了防止这种情况发生,我们在构造函数前加上explicit关键字,这样在你企图像上面那样赋值时,编译器就会给我们报错。
这里写图片描述

2、拷贝构造函数

拷贝构造函数

函数名与类名相同,无返回值,有一个形参(常用const修饰),该参数是本类类型的引用。是构造函数的重载,通过已经存在的对象来创建并初始化对象。

class Time
{
public:
    //构造函数
    Time(int hour = 0, int minute = 0, int second = 0)
        :_hour(hour)
        ,_minute(minute)
        ,_second(second)
    {
        doSomeThing...
    }

    //拷贝构造函数
    Time(const Time& t)
        :_hour(t._hour)
        ,_minute(t._minute)
        ,_second(t._second)
    {
        doSomeThing...
    }

private:
    int _hour;
    int _minute;
    int _second;
};

使用场景

1、使用已经存在的对象创建新的对象

Time t1(12,01,59);
Time t2(t1);

2、传值方式作为函数的参数

void FunTest1(const Time t)
{}

3、传值方式作为函数返回值

Time FunTest2()
{
    Time t;
    return t;
}

浅拷贝和深拷贝

对于普通类型的数据,它们之间的拷贝是很简单的,比如:

int a = 10;
int b = a;

而类类型的对象,由于它们内部有着复杂的结构,所以就不能使用简单的赋值运算就完成。

class String
{
    //构造函数
    ...

    //拷贝构造
    String(const String& s)
        :_pStr(s)
    {
        doSomeThing...
    }

private:
    char* _pStr;
};

浅拷贝
像上面这种做法,只是简单的将s赋给 _pStr,即让 _pStr也指向字符串s,这样造成的后果是多个对象指向同一空间,析构(关于析构的概念在下面介绍)出错,这种拷贝方式叫做浅拷贝
注意:系统默认合成的为浅拷贝,在大多数情况下,我们应该自己写出拷贝构造函数,即使系统会给我们合成它。

对于上面这种情况,我们需要主动给他重新开辟空间

class String
{
    //构造函数
    ...

    //拷贝构造函数
    String(const String& s)
        :_pStr(new char[strlen(s._pStr)+1])
    {
        strcpy(_pStr, s._pStr);
        doSomeThing...
    }

private:
    char* _pStr;
};

深拷贝
像这样,给新创建的对象开辟一块独立的空间,再将旧对象的内容拷贝过来,这样就不会发生如上的错误了,这种拷贝方式叫作深拷贝。

3、析构函数

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

class String
{
    //构造函数
    String(const char* pStr = '')
    {
        if(NULL == pStr)
        {
            _pStr = new char[1];
            *pStr = '\0';
        }
        else
        {
            _pStr = new char[strlen(pStr)+1];
            strcpy(_pStr, pStr);
        }
    }

    //析构函数
    ~String()
    {
        if(_pStr)
        {
            delete[] _pStr;
            _pStr = NULL;
        }
    }

private:
    char* _pStr;
};

如上所示,我们在创建对象时,给对象申请了空间,申请的空间必须手动去释放,所以我们在析构函数中去释放空间。
析构函数在对象生命周期结束前由系统自动调用。

4、赋值操作符(=)重载

普通类型之间的赋值通过简单的=完成

int a = 10;
int b = 20;
a = b;

对于类类型的对象我们需要对‘=’重载,以完成类类型对象之间的赋值。

class String
{
    //构造函数
    ...

    //拷贝构造
    ...

    //赋值运算符重载
    String& operator=(String s)
    {
        std::swap(_pStr, s._pStr);
        return *this;
    }

private:
    char* _pStr;
};

重载的格式:返回值为该类类型的引用,通过operator关键字后加上要重载的符号完成,它视情况也有参数。
如同上面拷贝构造函数那样,赋值运算符重载也存在深浅拷贝的问题,上例中直接给出深拷贝的重载。

5、取址(&)运算符重载

String* operator&()
{
    return this;
}

取址操作符重载函数返回值为该类型的指针,无参数。

6. const修饰的取址运算符重载

const String* operator&() const
{
    return this;
}

5中不同的是在函数名前和函数体前各加一个const


【作者:果冻 http://blog.csdn.net/jelly_9

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值