• 类和对象收尾


    本文主要内容:

    • 初始化列表
    • 静态成员,成员函数
    • 友元

    1.初始化列表
    今天我们来进行类和对象的收尾,相比于前面的构造函数和析构函数来说,这篇文章的内容相对是比较好理解的。我们这篇博客就来提一提静态成员,成员函数还有前面稍微提到的初始化列表。
    所谓的初始化列表就是成员变量被定义的地方!你可能会有疑问,在构造一个对象的时候,整个对象都出来了,为什么还要特意给成员变量找一个定义的地方。有这个疑问是很正常的。来看看下面这段代码:

    class Demo
    {
    private:
    	int _a;
    	const int _b;//const常量必须在定义的时候初始化
    	int& _rc;//引用也必须在定义的时候初始化
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    正是因为有的类的成员变量必须在定义的时候就要初始化,所以才必须找一个定义的地方。而成员定义的地方正好就是初始化列表,所以这个Demo类的构造函数可以这么写:

    class Demo
    {public:
    	Demo(int a=4)
    		: _a(4)
    		, _b(3)
    		, _rc(a)
    	{}
    private:
    	int _a;
    	const int _b;
    	int& _rc;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    也就是说,每一次调用构造函数,所有的成员变量都会走一次初始化列表。不仅如此,初始化列表还可以应用在下面这种情况:

    //初始化列表解决无法生成默认构造函数的问题
    class A
    {  public:
    	A(int x)
    	{
    		_x = x;
    	}
    private:
    	int _x;
    };
    class Demo
    {public:
    	Demo(int a=4)
    		: _a(4)
    		, _b(3)
    		, _rc(a)
    		,_aa(5)
    	{}
    private:
    	int _a;
    	const int _b;
    	int& _rc;
    	A _aa;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    本来正常情况下,我们是没有办法提供Demo类的默认构造函数,因为类A没有默认构造函数,但是利用初始化列表我们就可以很好解决这个问题。
    另外,初始化列表的初始化顺序只和类成员的声明顺序有关,而和初始化顺序无关

    class B
    {
    public:
    	B()
    		:_b1(4)
    		,_b2(_b1)
    	{}
    private:
    	int _b2;
    	int _b1;
    };
    int main()
    {   B b;
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    打开监视窗口,观察到如下的信息:
    在这里插入图片描述
    如果初始化列表里面的顺序来看,最后_b1,_b2的值应该都被初始化成4,但是很明显这里的_b2却是随机值。因为初始化列表的初始化是按照成员声明的顺序来的!所以说这里先用_b1初始化_b2,因此_b2是随机值!在使用初始化列表的时候要特别注意这一点。


    2.静态成员,静态成员函数
    前面我们类所拥有的成员都是依赖于实例化对象的。那么在C++里面还提供了一种特殊的机制---->静态成员,静态成员函数,那么这两个东西是不需要依赖对象---->可以理解成,静态成员和静态成员函数为所有类对象所共有的。
    我们可以来看一看具体的静态成员怎么定义:

    class C
    { 
    private:
    	int _a;
    	static char _c;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    那么静态成员的初始化比较特殊,由于静态成员的特殊性,因此静态成员并不会在初始化列表定义。我们必须显式自己初始化静态成员。

    //这里为了演示,把静态成员放出来
    class C
    {   privateint _a;
    	public:
    	static char _c;
    };
    //静态成员必须类外初始化,因为静态成员不会走初始化列表
    C::_c=1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    讲完了静态成员,我们在来看看静态成员函数,语法声明也是在成员函数前面加一个static关键字。

    class Demo
    {
      public:
      //这就是一个静态的成员函数
        static void show()
        {
          cout<<"hello world!"<<endl;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    访问静态成员函数的方法有两种:

    1.使用实例化对象访问
    2.使用类名::函数名进行访问

    思考两个问题:

    1.普通成员函数能否调用静态成员函数?
    2.静态成员函数能否调用普通成员函数?

    答案是:普通成员函数可以调用静态成员函数,而静态成员函数不能普通成员函数。因为,静态成员函数没有this指针!


    3.友元
    以日期类为例,有的时候我们希望通过键盘输入来构造日期类对象,那么我们就需要对日期类进行流提取运算符的重载,假如我们把流提取运算符重载成成员函数

    class Date
    {
    public:
    	Date(int year = 1900, int month = 1, int day = 1)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    	Date(const Date& d)
    	{
    		if (this != &d)
    		{
    			_year = d._year;
    			_month = d._month;
    			_day = d._day;
    		}
    	}
    	Date& operator=(const Date& d)
    	{
    		if (this != &d)
    		{
    			_year = d._year;
    			_month = d._month;
    			_day = d._day;
    		}
    		return *this;
    	}
    	//标准库流对象
    	istream& operator>>(istream& in)
    	{
    	    in>>_year>>_month>>_day;
    	    return in;
    	}
    
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    //具体调用
    int main()
    {
       Date d1;
       //cin>>d1是错误的
       d1>>cin;//这个是正确调用!
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    出现这种情况的原因就是:两个操作数的函数,编译器会自动把左操作数作为第一个参数。而成员函数的第一个参数永远是this指针,我们没办法更改!所以为了我们能够写法更加自然和易于理解,最好能重载全局的流提取运算符。但是又有一个问题。私有的成员变量外部无法直接访问。因此C++提供了一种特殊的机制来解决---->友元
    我们先来看一看怎么使用友元来使得访问私有成员:

    class Date
    {
    public:
      //友元声明---->friend关键字
      friend istream& operator>>(Date& d);
    	Date(int year = 1900, int month = 1, int day = 1)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    	Date(const Date& d)
    	{
    		if (this != &d)
    		{
    			_year = d._year;
    			_month = d._month;
    			_day = d._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;
    };
    //重载全局的流提取
    istream& operator(Date& d)
    {
       in>>d._year>>d._month>>d._day;
       return in;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    经过上面的操作以后,我们就可以使用cin来提取日期类的信息了!
    友元有以下几个注意的地方:

    • 友元关系是单向的,A是B的友元,但是B的友元不是A!
    • 友元没有传递性!
    • 友元会破坏封装,尽量避免使用友元

    总结

    • 初始化列表是成员定义的地方
    • 静态成员,函数是属于类的,静态成员函数没有this指针
    • 友元的简单使用

    本文的主要内容就到这里,如有不足支持还望指出,希望大家一起共同进步!

  • 相关阅读:
    网络安全(黑客)自学
    ES、kibana、JavaClient详细安装及操作
    Vue组件详解
    【docker】Docker打包SpringBoot镜像
    解决GoLand无法Debug
    国家网络安全周 | 保障智能网联汽车产业,护航汽车数据安全
    签到功能完成03《ivx低代码签到系统制作》
    Two Permutations
    EventLoop同步异步,宏任务微任务笔记
    六分科技CEO李阳:精准定位助力汽车智能化普及
  • 原文地址:https://blog.csdn.net/qq_56628506/article/details/125478000