C++:const,构造函数(补充),static,友元和内部类

一丶const成员

       

1.const成员函数

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

#include<iostream>
using namespace std;
class Date {
public:
	Date(int year = 2024, int month = 2, int day = 14) :
		_year(year), _month(month), _day(day){}


	void RevisionDateYear() const // 实际上理解void RevisionDateYear(const Date *this) 
	{
		int year = 2023;
		this->_year = year;   //这里在编译过程就会出错
	}


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

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

class Date{ 
public:
    Date* operator&()
    {
        return this;
    }
    const Date* operator&()const
    {
        return this;
    }
private:
    int _year; 
    int _month; 
    int _day; 
};

       这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容。

二丶补充构造函数

1.初始化列表

        初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。每个成员只能初始化一次,并且  引用  成员变量,const  成员变量和 自定义类型成员(且该类没有默认构造函数时)

#include<iostream>
using namespace std;
class Time {
public:
	void PrintTime()
	{
		cout << _hour << ":" << _minute << ":" << _second << endl;
	}
	Time(int hour,int minute,int second)
		:_hour(hour),_minute(minute),_second(second)
	{}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date {
public:
	Date(int month,int day,int hour = 8,int minute = 55,int second = 55)
		:_year(2024),_month(month),_day(day),_time(hour,minute,second)
	{}
	void PrintDate()
	{
		cout << _year << "-" << _month << "-" << _day << "-";
		_time.PrintTime();
	}
private:
	const int _year;     //const成员
	int &_month;          // 引用
	int _day;
	Time _time;           //没有默认构造函数的自定义类型
};
int main()
{
	Date d(2,19);            //缺省了,可以自己加上时分秒
	d.PrintDate();
	return 0;
}

       尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量, 一定会先使用初始化列表初始化。初始化时的顺序跟初始化列表的顺序没有关系,是按照成员声明的顺序来初始化的(比如上面就是按照priavte后面的顺序)。

2.explicit关键字

       构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。

class Date
 {
 public:
// 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
// explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译
explicit Date(int year)
 :_year(year)
 {}
 /*
 // 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具
有类型转换作用
// explicit修饰构造函数,禁止类型转换
explicit Date(int year, int month = 1, int day = 1)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
 */
 Date& operator=(const Date& d)
 {
 if (this != &d)
 {
 _year = d._year;
 _month = d._month;
 _day = d._day;
 }
 return *this;
 }
 private:
 int _year;
 int _month;
 int _day;
 };
 void Test()
 {
 Date d1(2022);
 // 用一个整形变量给日期类型对象赋值
// 实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值
d1 = 2023;
 /*  将1屏蔽掉,2放开时则编译失败,因为explicit修饰构造函数,禁止了单参构造函数类型转
换的作用  */
}

三丶static成员函数

1.概念

       声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用 static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。

#include<iostream>
using namespace std;
class Date {
public:
	Date(int y,int m, int d)
		: _year(y),_month(m),_day(d)
	{}
	int GetMonthDay()
	{
		return MonthDay[_month];
	}
private:
	int _year;
	int _month;
	int _day;
	static int MonthDay[13];
};
int Date::MonthDay[13] = { 0,1,2,3,4,5,6,7,8,9,10,11,12 };  //数据乱写的,类外初始化
int main()
{
	Date d(2024,2,19);
	cout << d.GetMonthDay() << endl;
	return 0;
}

2.特性

(1). 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区

(2). 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明

(3). 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问

(4). 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

(5). 静态成员也是类的成员,受public、protected、private 访问限定符的限制

四丶友元

1.友元函数

       在上一篇重载的内容已经提到过,现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成 全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。

       友元,假设一个类是你的带锁的箱子,private类型的成员就是被锁住的东西,友元就是备份钥匙,这样友元函数也可以访问private类型了。声明时记得带上friend

#include<iostream>
using namespace std;
class Date {
public:
	Date(int y,int m, int d)
		: _year(y),_month(m),_day(d)
	{}
	int GetMonthDay()
	{
		return MonthDay[_month];
	}
    friend ostream& operator<<(ostream& out,const Date d);
private:
	int _year;
	int _month;
	int _day;
	static int MonthDay[13];
};

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

int Date::MonthDay[13] = { 0,1,2,3,4,5,6,7,8,9,10,11,12 };  //乱写的,类外初始化
int main()
{
	Date d1(2024,2,19);
	Date d2(2024,2,20);
    cout<<d1<<d2<<endl;
	return 0;
}

       在最开始已经解释了,疑惑的地方肯定是 函数内部return out ,这是为了能够连续输出(输入也是这样)。cout<<d1<<d2 == (operator<<(cout, d1)) << d2,就是cout和d1作为参数先调用了重载函数,返回out(实际上还是cout) 和 d2又调用了重载函数。

       友元函数可访问类的私有和保护成员,但不是类的成员函数。 友元函数不能用const修饰友元函数。可以在类定义的任何地方声明,不受类访问限定符限制。一个函数可以是多个类的友元函数 友元函数的调用与普通函数的调用原理相同  

2.友元类

       和友元函数类似,友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

(1).友元类的关系时单向的,比如Date声明为Time 的友元类,Date可以访问Time,但是Time不能访问Date。

(2).友元关系不能传递,A是B的友元类,B是C的友元类,但是A不是C的友元类

#include<iostream>
using namespace std;
class Time {
	friend class Date;
public:
	Time(int hour,int minute,int second)
		:_hour(hour),_minute(minute),_second(second)
	{}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date {
public:
	Date(int month ,int day,int hour = 10,int minute = 55,int second = 55)
		:_year(2024),_month(month),_day(day),_time(hour,minute,second)
	{}
	void PrintDate()
	{
		cout << _year << "-" << _month << "-" << _day << "-"
			 << _time._hour << "-" << _time._minute << "-" << _time._second;  
                        //可以直接访问,没有用友元函数                 
	}
private:
	const int _year;
	int &_month;
	int _day;
	Time _time;
};
int main()
{
	Date d(2,19);
	d.PrintDate();
	return 0;
}

五丶内部类

1.概念:

       如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类, 它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越 的访问权限。

2.注意:

       内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访 问外部类中的所有成员。但是外部类不是内部类的友元。

3.特性:

(1). 内部类可以定义在外部类的public、protected、private都是可以的。

(2). 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

(3). sizeof(外部类)=外部类,和内部类没有任何关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值