99网
您的当前位置:首页【C++】:类和对象(中):const成员 || 取地址及const取地址操作符重载

【C++】:类和对象(中):const成员 || 取地址及const取地址操作符重载

来源:99网

📪1.const成员

📪将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

📟输入的语法规则则为

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

📮见下图能否帮助你理解一下

🔫2.取地址及const取地址操作运算符重载

🎾下面我们正式进入今天的主题
来看下面两段代码

//	const对象和非const对象都可以调用const成员函数
//	const Date d1(2023, 10, 31);
//	d1.Print();
//
//	Date d2(2023, 1, 1);
//	d2.Print();

#include "Date.h"

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;

	if (_year < 1 ||
		_month < 1 || _month > 12 ||
		_day < 1 || _day > GetMonthDay(_year, _month))
	{
		//assert(false);
		Print();
		cout << "日期非法" << endl;
	}
}

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

bool Date::operator==(const Date& y)  const
{
	return _year == y._year
		&& _month == y._month
		&& _day == y._day;
}

// d1 != d2
bool Date::operator!=(const Date& y) const
{
	return !(*this == y);
}

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

	return false;
}

bool Date::operator>=(const Date& y) const
{
	return *this > y || *this == y;
}

bool Date::operator<(const Date& y) const
{
	return !(*this >= y);
}

bool Date::operator<=(const Date& y)  const
{
	return !(*this > y);
}

int Date::GetMonthDay(int year, int month)
{
	assert(year >= 1 && month >= 1 && month <= 12);

	int monthArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31 };

	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		return 29;

	return monthArray[month];
}

// d1 += 100
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= (-day);
	}

	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);

		++_month;

		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}

	return *this;
}

Date Date::operator+(int day) const
{
	Date tmp(*this);
	tmp += day;

	return tmp;
}
// 
// d1 += 100
//Date& Date::operator+=(int day)
//{
//	//Date d = *this + day;
//	//*this = d;
//
//	*this = *this + day;
//	return *this;
//}
//
//Date Date::operator+(int day)
//{
//	Date tmp(*this);
//
//	tmp._day += day;
//	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
//	{
//		tmp._day -= GetMonthDay(tmp._year, tmp._month);
//
//		++tmp._month;
//
//		if (tmp._month == 13)
//		{
//			tmp._year++;
//			tmp._month = 1;
//		}
//	}
//
//	return tmp;
//}

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += (-day);
	}

	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			--_year;
			_month = 12;
		}

		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

Date Date::operator-(int day) const
{
	Date tmp(*this);
	tmp -= day;

	return tmp;
}

// ++d1
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

// d1++
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}


Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

Date Date::operator--(int)
{
	Date tmp(*this);
	*this -= 1;

	return tmp;
}

// d1 - d2
int Date::operator-(const Date& d) const
{
	// 假设左大右小
	int flag = 1;
	Date max = *this;
	Date min = d;

	// 假设错了,左小右大
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n * flag;
}

//void Date::operator<<(ostream& out)
//{
//	out << _year << "年" << _month << "月" << _day << "日" << endl;
//}

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;

	return out;
}

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;

	return in;
}

🚿思考下面问题
📲1. const对象可以调用非const成员函数吗?
📲2. 非const对象可以调用const成员函数吗?
📲解析:能定义成const的成员函数都应该定义成为const 这样对const对象和非const成员来说都可以调用 要修改成员变量的成员函数不能定义成const
📲上述问题归根结底还是我们的权限的放大缩小和平移的问题

//class A
//{
//public:
//    A(int a)
//        :_a(a)
//    {
//        cout << "A(int a = 0)" << endl;
//    }
//private:
//    int _a;
//};
//
//namespace bit
//{
//    class Date
//    {
//    public:
//        //Date(int year, int month, int day)
//        //{
//        //    // 函数体内初始化
//        //    _year = year;
//        //    _month = month;
//        //    _day = day;
//
//        //    //_ref = year;
//        //    //_n = 1;
//        //}
//
//        //Date(int year, int month, int day)
//        //    :_year(year)
//        //    ,_month(month)
//        //    ,_day(day)
//        //    ,_ref(year)
//        //    ,_n(1)
//        //{
//        //    // 初始化列表
//        //    // 
//        //}
//
//        Date(int year, int month, int day)
//           :_year(2)
//           ,_ref(year)
//           ,_n(1)
//           ,_aa(10)
//        {
//            // 剩下3个成员没有在初始化列表显示写出来定义
//            // 但是他也会定义,只是内置类型默认给的随机值
//            // 如果是自定义类型成员会去调用它的默认构造函数
//            
//            // 函数体内初始化
//            _year = year;
//            _month = month;
//            _day = day;
//        }
//
//    private:
//        // 声明
//        int _year = 1; // 缺省值
//        int _month = 1;
//        int _day;
//
//        A _aa;        // 定义类型成员(且该类没有默认构造函数时)
//
//        int& _ref;	  // 引用 : 必须在定义的时候初始化
//        const int _n; // const : 必须在定义的时候初始化
//    };
//}

// 初始化列表解决的问题:
// 1、必须在定义的地方显示初始化  引用  const   没有默认构造自定义成员
// 2、有些自定义成员想要显示初始化,自己控制
// 尽量使用初始化列表初始化
// 构造函数能不能只要初始化列表,不要函数体初始化
// 不能,因为有些初始化或者检查的工作,初始化列表也不能全部搞定
// 80-100%初始化列表搞定,还有需要用函数体,他们可以混着用
class Stack
{
public:
    Stack(int n = 2)
        :_a((int*)malloc(sizeof(int)*n))
        ,_top(0)
        ,_capacity(n)
    {
        //...
        //cout << "Stack(int n = 2)" << endl;
        if (_a == nullptr)
        {
            perror("malloc fail");
            exit(-1);
        }

        memset(_a, 0, sizeof(int) * n);
    }

    //...

    int* _a;
    int _top;
    int _capacity;
};

📲上述代码给大家写了一下初始化列表和函数体的运用规则 对于const成员和引用成员必须在初始化列表初始化 不能再函数体内部初始化 初始化列表也可以运用函数 比如malloc 然后在函数体内判断是否为NULL 在进行memset操作
📲来看下面的一道面试题

class A
{
public:
    A(int a)
        :_a1(a)
        , _a2(_a1)
    {}

    void Print() {
        cout << _a1 << " " << _a2 << endl;
    }
private:
    int _a2;
    int _a1;
};

int main() 
{
    A aa(1);
    aa.Print();
}

因篇幅问题不能全部显示,请点此查看更多更全内容