隐式this指针及C++类中六个默认成员函数

隐式指针->this指针

什么叫隐式指针?
它其实就是在对象实例化以后,在传参的时候默认传过去的一个对象的地址
怎么理解这句话呢?
比如:我们的拷贝构造函数(不知到拷贝构造函数是干什么的可以往下看)

class Date
{
public:
    // 构造函数
    Date(int year = 1970, int month = 1, int day = 1) 
        :_year(year), _month(month), _day(day){}
    // 这里就不做日期判断

    // 拷贝构造函数
    // 这里有隐含this指针
    // 这里用const修饰是为了不希望在拷贝构造的时候修改我原有的值
    Date(const Date& d)     
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
    // 析构函数
    ~Date();

private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d;
    Date d1(d);
    return 0;
}

上面的拷贝构造函数,当d1对象拷贝d对象时候,本应该传入两个参数,但只有一个,这里就有一个隐式的this指针 ,所以在拷贝函数里面也有两个形参

Date(const Date& d) -》  Date(Date *this, const Date& d)
Date d1(d); -》  Date d1(&d1, d);

理解这个再理解运算符重载就很简单了。

C++中默认六个成员函数

1. 构造函数

2. 拷贝构造函数

3. 析构函数

4. 赋值操作符重载

5. 取地址操作符重载

6. const修饰的取地址操作符重载

构造函数
构造函数分为有参和无参,是用来初始化类中的成员变量,所以在实例化一个对象时,就自动调用构造函数进行初始化。
构造函数的特征:

  1. 函数名与类名相同
  2. 无返回值
  3. 对象在实例化过程中自动调用
  4. 构造函数可以重载
  5. 如果没有构造函数,系统会自动添加一个无参数的构造函数
  6. 无参构造函数和全缺省的构造函数否认为是缺省构造函数,并且缺省的构造函数只能有一个。

拷贝构造函数
这是用来对需要创建同类对象时进行初始化用的。比如有个对象d1,我们需要有一个和d1一样参数的对象,这时我们就需要用拷贝构造函数。
特征:

  1. 拷贝构造可以说是构造函数的一个重载
  2. 拷贝构造时必须要用引用传参,如果用传值方式会发生无穷递归调用
  3. 如果为定义,系统会自动生成一个缺省的拷贝构造。

析构函数
析构函数是在对象生命周期结束时,系统会调用它来对对象进行一些清理工作
析构函数不能重载
析构函数无返回值
如果未定义,系统会自动生成缺省的析构函数

*运算符重载
运算符重载的特征:
poerator+合法运算符 构成运算符重载
注意:重载后不能改变运算符的优先级,结合性,操作数个数。

有五个运算符不能重载
.* / :: / sizeof / ?: / .

赋值运算符重载
这里要把赋值运算符重载和拷贝构造比较记忆
拷贝构造是创建对象时候,使用一个已有对象来为这个初始化
赋值运算的重载是对一个已经存在的对象进行拷贝赋值

到这里以日期类举例:

#include<iostream>
#include<windows.h>
#include<assert.h>
using namespace std;

class Date
{
public:
    // 默认六大基本函数

    // 构造函数>>你可以重载
    // Date(); // 不能和全缺省的构造函数共存
    Date(int, int, int);
    bool IsLeapYear(int); // 判断是否是闰年
    int GetMonthDay(int, int); // 得到该月的天数

    // 拷贝构造函数
    // 这里有隐含this指针
    Date(const Date& d) // 这里用const修饰是为了不希望在拷贝构造的时候修改我原有的值
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }

    // 赋值操作符重载
    // d1 = d2;函数栈帧结束,变量未释放&
    // 不加Date&中的&,会多调用一次拷贝构造
    Date& operator=(const Date& d) // 这个就相当于 Date& operator=(Date *this, const Date&d)
    {
    // 这里是如过要拷贝的对象是自己本身那么就不用拷贝直接返回
        if (this == &d) 
        {
            return *this;
        }
        // 这里有隐含的this指针
        _year = d._year;
        _month = d._month;
        _day = d._day;
        return *this;
    }


    ////////////////////////////
    // 运算符重载
    // 判断是否相等。
    bool operator==(const Date& d)
    {
        if (_year == d._year && _month == d._month && _day == d._day)
        {
            return true;
        }
        return false;
    }

    bool operator!=(const Date& d)
    {
        if (!(*this == d))
        {
            return true;
        }
        return false;
    }

    bool operator>(const Date& d)
    {
        if (_year > d._year)
        {
            return true;
        }
        else if (_month > d._month)
        {
            return true;
        }
        else if (_day >d._day)
        {
            return true;
        }
        return false;
    }

    bool operator>=(const Date& d)
    {
        if (*this == d || *this > d)
        {
            return true;
        }
        return false;
    }

    bool operator<(const Date& d)
    {
        if (!(*this >= d))
        {
            return true;
        }
        return false;
    }

    bool operator<=(const Date& d)
    {
        if (*this < d || *this == d)
        {
            return true;
        }
        return false;
    }

    // 日期加上一个天数,d1 + 10;
    // 不改变原来的d1,所以不能用引用
    Date operator+(int day)
    {
        Date ret(*this);
        if (day < 0)
        {
            ret -=(-day);
            return ret;
        }
        ret._day += day;
        while (GetMonthDay(ret._year, ret._month) < ret._day)
        {
            ret._day -= GetMonthDay(ret._year, ret._month);

            if (ret._month == 12)
            {
                ret._month = 1;
                ++ret._year;
            }
            else
            {
                ++ret._month;
            }
        }
        return ret;
    }

    // 加等d1 = d1 + 10;
    // 可以用引用,出了作用于变量还在
    Date& operator+=(int day)
    {
        *this = *this + day;
        return *this;
    }

    // 前置++和后置++
    // 前置++
    Date& operator++()
    {
        *this = *this + 1;
        return *this;
    }
    // 后置++
    Date operator++(int)// 用这样的方式来区分
    {
        Date ret(*this);
        *this = *this + 1;
        return ret;
    }

    // 日期减上天数
    // 不能用引用
    Date operator-(int day)
    {
        Date ret(*this);
        if (day < 0)
        {
            ret += (-day);
            return ret;
        }
        ret._day -= day;
        while (ret._day <= 0)
        {
            if (ret._month == 1)
            {
                --ret._year;
                ret._month = 12;
            }
            else
            {
                --ret._month;
            }
            // 因为前面已经相减为负数,所以要相加
            ret._day += GetMonthDay(ret._year, ret._month);
        }
        return ret;
    }

    // 前置--和后置--
    // 前置--
    Date& operator--()
    {
        *this = *this - 1;
        return *this;
    }

    // 后置--
    Date operator--(int)
    {
        Date ret(*this);
        *this = *this - 1;
        return ret;
    }

    Date& operator-=(int day)
    {
        *this = *this - day;
        return *this;
    }

    // 日期减去日期,求中间所差几天
    int operator-(const Date& d)
    {
        int count = 0;

        if (*this < d)
        {
            Date tmp(*this);
            while (tmp != d)
            {
                ++count;
                ++tmp;
            }
        }
        else
        {
            Date tmp(d);
            while (tmp != *this)
            {
                ++count;
                ++tmp;
            }
        }
        return count;
    }

    // 以上就是运算符重载
    /////////////////////////////
    void Print();

    // 析构函数
    ~Date();

private:
    int _year;
    int _month;
    int _day;
};

// 无参数构造函数 >> 并且你不能和全缺省构造参数一块出现
// Date::Date(){}

// 全缺省构造函数
Date::Date(int year = 1970, int month = 1, int day = 1) :_year(year), _month(month), _day(day)
{
    if (!(year > 0 && month > 0 && month < 13 && day > 0 && day <= GetMonthDay(year, month)))
    {
        assert(false);
    }
    /*_year = year;
    _month = month;
    _day = day;*/
}

bool Date::IsLeapYear(int year)
{
    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
    {
        return true;
    }
    return false;
}

int Date::GetMonthDay(int year, int month)
{
    int days[13] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    int day = days[month];
    if (day == 2 && IsLeapYear(year))
    {
        day = 29;
    }
    return day;
}

void Date::Print()
{
    cout << _year << "-" << _month << "-" << _day << endl;
}

// 你不能重载
Date::~Date(){}


int main()
{
    Date d;
    d.Print();
    Date d1(2017, 2, 20);
    d1.Print();
    Date d2(2017, 2, 29);
    d2.Print();
    cout << d1.operator-(d2) << endl;
    Date d3;
    d3 = d2;
    d3.operator+= (-100);
    d3.Print();
    system("pause");
    return 0;
}

取地址操作符重载
这个重载和const修饰的取地址操作符重载相比前面四种默认函数,用的频率不是很高,一般系统生成的默认函数就够用了,但是这还是得了解。
就用日期类来说:Date *operator&(){} 这就是&重载。
const修饰的取地址操作符重载
先举例子
const Date *operator() const
如果了解const,就知道怎么用了,如果不了解,继续往下看。

最后两个默认成员函数后续继续更新

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值