C++默认成员函数(三)

一.const权限

之前我们学过const的用法,当其修饰一个变量时,变量的值不能再发生改变,当其修饰指针时,分两种情况,放在*前面的,指向的值不再发生改变,*后面指向不再发生改变,现在我们再来学习下引用相关的内容。

权限的缩小:

int main()
{
    int a = 10;
    //权限的缩小是可以的
    const auto& b = a;

    return 0;
}

C++默认成员函数(三)_第1张图片

权限的放大是不行的

权限的保持:

int main()
{
    const int& a = 10;
    //此时,
    const int& b = a + 10;
    return 0;
}

总结:

const修饰时,权限只能维持不变或者减小,绝对不能增大

二.赋值运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其
返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)

 

例如:

//operator运算符 做函数名
bool operator==(const Date& x, const Date& y)
{
    return x._year == y._year
        		&& x._month == y._month
        		&& x._day == y._day;
}

我们可以利用上面函数来做如下测试:

class Date
{
public:
    Date(int year, int month, int day)
    {
        this->_year = year;
        this->_month = month;
        this->_day = day;
    }
    /*bool operator==(const Date& x, const Date& y)
    {

    }*/
//private:
    int _year;
    int _month;
    int _day;
};
//operator运算符 做函数名
bool operator==(const Date& x, const Date& y)
{
    return x._year == y._year
        		&& x._month == y._month
        		&& x._day == y._day;
}
int main()
{
    Date s1(2024, 1, 29);
    Date s2(2024, 2, 30);
    cout << (s1 == s2) << endl;
    return 0;
}

结果:

C++默认成员函数(三)_第2张图片

上面的内容足以让我们走进这扇大门:

运算符重载写法为:

类型+operator+运算符符号+形参
 

如果你足够细心,就会发现我们的函数是写在外面的,导致我们private被迫去除,否者我们无法访问到成员变量,所以正确的写法为:放在类中。

class Date
{
public:
    Date(int year, int month, int day)
    {
        this->_year = year;
        this->_month = month;
        this->_day = day;
    }
    bool operator==(const Date& y)
    {
        return this->_year == y._year
                   && this->_month == y._month
                		&& this->_day == y._day;
    }
private:
    int _year;
    int _month;
    int _day;
};

要注意的是放在类内部,我们的形参要减少一个,原因是this指针指向第一个参数

关于赋值运算符重载注意事项:
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型参数
用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this
.*   ::   sizeof    ?:   .    注意以上5个运算符不能重载。这个经常在笔试选择题中出现

第一个是( .*  ),别看成了(*---可以重载的)

再写一个大家可以再看看是否掌握:

    bool operator<(const Date& y)
    {
        if (this->_year < y._year)
            return true;
        else if(this->_year==y._year)
        {
            if (this->_month < y._month)
                return true;
            else if (this->_month == y._month)
            {
                if (this->_day < y._day)
                    return true;
            }

        }
        return false;
    }

现在关于如何定义我们是会了,那么该如何调用呢?

我们通过代码引入:

int main()
{
    Date s1(2024, 1, 29);
    Date s2(2024, 2, 30);
    //常见的三种写法:
    //第一种:正常的函数调用即可,只适合于我们写在了类外面的情况
    cout << (operator==(s1, s2)) << endl;
    //第二种写法:调用类成员函数写法
    cout << s1.operator<(s2) << endl;
    //第三种写法:我们可以直接简写要比较的函数即可,IDE会自动识别帮我们调用
    //但是要注意的是:<<的运算符级别较高,通常需要加()
    cout << (s1 == s2) << endl;//等价为:operator==(s1,s2)/s1.operator(s2)
    cout << (s1 < s2) << endl;
    return 0;
}

所以大体上赋值运算符重载格式如下:
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回*this :要复合连续赋值的含义

 

Date& operator=(const Date& y)
{
    if (this != &y)//检查是否为自己给自己赋值情况
    {
        this->_year = y._year;
        this->_month = y._month;
        this->_day = y._day;
    }
    return *this;
}

这个就是六大默认成员函数之一的赋值重载函数

要注意的是:

赋值运算符只能重载成类的成员函数不能重载成全局函数
用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注
意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符
重载完成赋值

 

该默认函数和拷贝构造规律大体相似,分为浅拷贝和深拷贝

关于我们是否需要自己实现,如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现
 

下面我们对两者进行区分:

class Date
{
public:
    Date(int year, int month, int day)
    {
        this->_year = year;
        this->_month = month;
        this->_day = day;
    }
    Date(const Date& y)
    {
        cout << "是拷贝构造" << endl;
    }
    Date& operator=(const Date& y)
    {
        if (this != &y)//检查是否为自己给自己赋值情况
        {
            this->_year = y._year;
            this->_month = y._month;
            this->_day = y._day;
        }
        return *this;
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date s1(2024, 1, 31);
    Date s2(s1);
    return 0;
}

现在我们的s2如果是调用拷贝构造会显示“是调用拷贝构造”这几个字,如果是调用赋值重载,就什么都不会显示,那么你觉得结果是什么呢?

C++默认成员函数(三)_第3张图片

说明我们这种写法确实是在调用拷贝构造,那么怎么调用赋值重载呢?两者有什么区别呢?

int main()
{
    Date s1(2024, 1, 31);
    //Date s2(s1);
    Date s2;
    //调用的两种方法:
    // 1.直接赋值调用
    s2 = s1;
    //成员函数调用法
    s2.operator=(s1);    
    s1.print();
    s2.print();
    return 0;
}

上面就是对于复制重载的调用方法

关于问题二:

相信大家现在对比两者代码也会发现,在拷贝构造函数中我们是直接对一个创建的变量做初始化,而在复制重载里面我们是对一个已存在的变量做赋值处理

所以区别为:

拷贝构造,同类型一个存在的对象进行初始化要创建的对象

复制重载,已经存在的对象,一个拷贝赋值给另一个已存在的变量

赋值我们的规则是可以连续赋值的,那么我们的函数该如何实现连续赋值呢?

其实该函数就可以处理连续赋值问题,例如:s1=s2=s3,计算机会先将s3的值赋值给s2,在将s2的值赋值给s1,从而达到连续赋值效果

关于复制重载,我们还有两个特例:

--和++,大家都知道我们通常讲该两者分为前置和后置,那么我们如何实现不同的复制重载效果呢?

C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递

 

class Date
{
public:
    Date(int year=2024, int month=1, int day=29)
    {
        this->_year = year;
        this->_month = month;
        this->_day = day;
    }
    //前置++
    Date& operator++()
    {
        this->_day++;
        //……后序处理我们先不写
        return *this;
    }
    //后置++
    Date operator++(int)
    {
        Date tmp;
        tmp = *this;
        //Date tmp(*this);
        this->_day++;
        return tmp;
    }
private:
    int _year;
    int _month;
    int _day;
};

--同理,大家可以自行去实现!

最后,感谢大家的支持!

你可能感兴趣的:(c++,开发语言)