💖作者:小树苗渴望变成参天大树
❤️🩹作者宣言:认真写好每一篇博客
💨作者gitee:gitee
💞作者专栏:C语言,数据结构初阶,Linux,C++
文章目录
- 前言
- 一、案例的引入
- 二、const对象和成员函数
- 三、取地址及const取地址操作符重载
- 四、总结
前言
今天我们来讲讲const对成员对象和成员函数都有那些要注意的细节,还有两个默认成员函数的简单讲解,内容不是特别难,对于const大家要熟悉引用中对于权限的放大,缩小,平移的理解,可以参考这篇引用的第6.5节讲的内容,再来理解这个就好理解一点,那我们开始进入正文的讲解
一、案例的引入
我们其实已经接触过了一点关于const修饰对象的案例了,再讲解输入输出运算符重载的博客中,全局的重载函数访问私有的成员有两种方法,一个使用友元,一个使用共有的成员函数将值返回出来,第二种方法
我们当时说为什么这个不加const修饰,主要原因是类型的不匹配,对于我们成员函数,我们再类和对象的第一篇博客就讲解到过,每个正常成员函数都有一个隐藏的this指针(有的用static修饰的成员函数就没有this指针,所以这里说正常的成员函数),对于隐藏的this指针他的类型为类名+*+this(以日期类为例:date * this),准确来说,他的类型为(*date const this)修饰的this本身不变修改,当时没说明是怕大家不理解,这里再提出来,对于上图的案例,其实应该写成这样的:
通过这个图,大家应该差不多明白了为什么上面不加const了吧,大家有了这方面的了解之后,我们再来细看
二、const对象和成员函数
再上面我们如果想传const的对象应该怎么办,this指针本身就是隐藏的,所以没有办法显示的加const,那么祖师爷针对这个问题就规定了再括号后面加一个const,例如:
class Date
{
public:
Date(int year=1, int month=1, int day=1)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << "Print()" << endl;
}
void Print() const
{
cout << "Print()const" << endl;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
我们来测试一下:
我们来看看加const的成员函数能不能调用普通对象:
因为从Datethis传给const Datethis是权限的缩小,所以可以,反过来就不行,既然这样有的人就像把全部的成员函数都加一个const这样不是更好吗??其实并不是,对于那些不修改对象的成员函数可以加,效果更好,修改自身不可以加
这个const对象d2无法调用非const的成员函数,原因就是权限的放大了,const对象没有办法传给非const的this
通过上面的案例
- const对象不可以调用非const成员函数
- 非const对象可以调用const成员函数 **
我们来看看之前写了日期类那些可以加:
class date
{
public:
date(int year = 1, int month = 1, int day = 1)//全缺省的构造函数
{
if (day > 0 && day <= getmonthday(year, month) && month > 0 && month < 13)
{
_year = year;
_month = month;
_day = day;
}
else
{
cout << "非法初始化" << endl;
assert(false);
}
}
//拷贝构造
//赋值重载
//析构函数
void print()const//当成内联函数
{
cout << _year << " " << _month << " " << _day << endl;
}
bool operator<(const date& d)const;
bool operator==(const date& d)const;
bool operator>(const date& d)const;
bool operator>=(const date& d)const;
bool operator<=(const date& d)const;
bool operator!=(const date& d)const;
date& operator+=(int day);
date operator+(int day)const;
static int getmonthday(int year, int month);
// 日期-天数
date operator-(int day)const;
// 日期-=天数
date& operator-=(int day);
// 前置++
date & operator++();
// 后置++
date operator++(int);
// 后置--
date operator--(int);
// 前置--
date& operator--();
int operator-(const date& d)const;
int getyear()const
{
return _year;
}
int getmonth()const
{
return _month;
}
int getday()const
{
return _day;
}
friend ostream& operator<<(ostream& cout, const date& d);
friend istream& operator>>(istream& cin, date& d);
再定义的地方也要加const
不加会出现那些情况:
大家看这样就比较不了,原因是小于里面的隐藏this不是const修饰类型,而运算符的第一个参数默认传给this的,第二不行的原因是,d2是const修饰类型,传给的this是普通的类型,是权限的放大,所以不行
所以必须要在小于那里加const:
所以有的时候不加还是不行的,根据具体实际来写
- 要修改成员变量的函数不能加
- 只要成员函数内部不修改成员变量都应该加const,这样const对象和普通对象都可以调用
其实对于单个函数需不需要使用const很好判断的,但是对于函数复用,就很麻烦,我们来看看下面两个问题:(这样自己再理解一下日期类那些函数加const的特性)
-
const成员函数内可以调用其它的非const成员函数吗?
-
非const成员函数内可以调用其它的const成员函数吗?
大家应该看到想要的结果了吧,在日期类中,我们的小于和等于是自己实现的,其余的都是复用这两个函数,如果这两个不加const,其余的都不能加,加了就会报错。
只要复用了小于和等于的函数都需要加const,不然就会报错,所以大家在写日期类的时候要主要了,如果有的函数用的时候保存,大概路是类型传参不匹配,往前面检查就行了。这个在后面也会遇到的,现在大家理解起来还是有点困难的。
三、取地址及const取地址操作符重载
我们在类和对象中篇的时候,讲过我们有六个默认成员函数,之前已经讲过了四个,现在还剩两个,这两个几乎很少需要自己实现,默认生成的就可以完成需求,这两个没啥可以讲的,就是取到对象的地址
class Date
{
public :
Date* operator&()
{
return this ;
}
const Date* operator&()const
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
const的取地址运算符就是为了取出const对象的地址,这里面有一个注意的细节,我们的d2对象是const修饰的,所以必须初始化,因为只有一次初始化的机会。我这里直接给缺省值,调用构造函数就行了。
自己手写这个函数,可能不想让别人得到对象的地址,返回一个假的数据给他:
大家知道了解就好,以后开发几乎不咋需要自己实现
这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!
四、总结
到这里我们的类和对象中篇算是讲解完了,里面的内容非常的多,尤其是细节方面的,大家一定要理解,画图,接下来我将讲解类和对象下篇的知识点,初始化列表是一个比较难的知识点,大家做好准备,我们下篇再见。