【c++】类和对象(六)深入了解隐式类型转换

2024-04-01 1191阅读

【c++】类和对象(六)深入了解隐式类型转换

🔥个人主页:Quitecoder

🔥专栏:c++笔记仓

【c++】类和对象(六)深入了解隐式类型转换

朋友们大家好,本篇文章我们来到初始化列表,隐式类型转换以及explicit的内容

目录

  • 1.初始化列表
    • 1.1构造函数体赋值
    • 1.2初始化列表
      • 1.2.1隐式类型转换与复制初始化
      • 1.3explicit关键字

        1.初始化列表

        1.1构造函数体赋值

        在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值

        class Date
        {
        public:
        Date(int year, int month, int day)
         {
             _year = year;
             _month = month;
             _day = day;
         }
        private:
        int _year;
        int _month;
        int _day;
        };
        

        虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值

        1.2初始化列表

        class Date {
        public:
        	Date(int year,int month,int day)
        		:_year(year)
        		,_month(month)
        		,_day(day)
        	{}
        private:
        	int _year;
        	int _month;
        	int _day;
        };
        

        初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式

        那么,为什么要使用初始化列表呢?它的优势在哪里呢?

        我们来看构造函数对于下面类的初始化:

        class Date2 {
        public:
        	Date2(int year, int month, int day)	
        	{
        	    _n=10;
        		_year = year;
        		_month = month;
        		_day = day;
        	}
        private:
        	int _year;
        	int _month;
        	int _day;
        	const int _n;
        };
        

        【c++】类和对象(六)深入了解隐式类型转换

        我们发现const成员变量并不能用函数体进行初始化

        int _year;
        int _month;
        int _day;
        

        这三个成员既可以在函数体,又可以在初始化列表,但是类中包含以下成员,必须放在初始化列表位置进行初始化:

        • 引用成员变量
        • const成员变量
        • 自定义类型成员(且该类没有默认构造函数时)
              int _year;
          	int _month;
          	int _day;
          	const int _n;
          

          我们知道,这个只是一个声明,定义是对象实例化时候完成的,有些成员,必须在定义的时候进行初始化

          初始化列表中的每个元素都直接对应一个成员变量或基类,允许在构造函数体执行之前对这些成员或基类进行初始化。这对于const成员变量、引用类型成员变量以及某些没有默认构造函数的类型尤其重要

          Date2(int year, int month, int day)	
          	:_n(1)
          {
          	_year = year;
          	_month = month;
          	_day = day;
          }
          

          初始化列表是每个成员变量定义初始化的位置

          class Date2 {
          public:
          	Date2(int year, int month, int day)	
          		:_n(1)
          	{
          		_year = year;
          		_month = month;
          		_day = day;
          	}
          private:
          	int _year;
          	int _month;
          	int _day;
          	const int _n;
          };
          

          没有在初始化列表中显式初始化_year、_month、和_day这三个成员变量,它们仍然会在初始化列表阶段被默认初始化,然后在构造函数体内被赋新的值

          对于基本类型(如int),如果它们未在类的初始化列表中显式初始化,则它们会进行默认初始化。对于类内的基本类型成员变量,默认初始化意味着不进行初始化(保留未定义值),除非它们是静态存储持续时间的对象(例如全局或静态变量,它们会被初始化为零)。然而,对于自动存储持续时间(如函数内的局部变量)的对象,如果未显式初始化,则其值是未定义的。在类构造函数中,成员变量的行为类似于局部变量,如果不在初始化列表中显式初始化,它们将不会被自动初始化

          _n是通过初始化列表初始化的,因为它是const类型的,必须在那里初始化。而_year、_month、和_day虽然没有在初始化列表中被显式赋值,但它们会在构造函数体开始执行前完成默认初始化(对于基本数据类型,这意味着它们的初始值是未定义的)。然后,在构造函数体内,它们被赋予新的值

          因此,可以说成员变量_year、_month、和_day先经历了默认初始化(在这个场景下,这意味着它们的值是未定义的),然后在构造函数体内被赋值

          我们不妨提到前面讲的声明时给缺省值:

          private:
          	int _year=1;
          	int _month;
          	int _day;
          	const int _n;
          

          缺省值的本质就是给初始化列表用的

          【c++】类和对象(六)深入了解隐式类型转换

          Date2(int year, int month, int day)	
              : _n(1), _year(year), _month(month), _day(day)
          {
              // 构造函数体可以留空,因为所有成员变量都已经在初始化列表中初始化
          }
          

          在这个版本中,所有成员变量都是通过初始化列表直接初始化的,这是推荐的做法,特别是对于复杂类型或类类型的成员变量

          引用类型必须在定义的时候初始化,所以也得使用初始化列表

          class A
          {
          public:
          	A(int a=0)
          		:_a(a)
          	{}
          private:
          	int _a;
          };
          class Date2 {
          public:
          	Date2(int year, int month, int day,int x)	
          		:_n(1)
          		,_year(year)
          		,_month(month)
          		,_day(day)
          		,_ref(x)
          	{
          	}
          private:
          	int _year=1;
          	int _month;
          	int _day;
          	const int _n;
          	int& _ref;
          	A aa;
          };
          

          这里aa也会走初始化列表,来调用它的默认构造函数

          【c++】类和对象(六)深入了解隐式类型转换

          我们可以在初始化列表来直接控制自定义类型的初始化

          Date2(int year, int month, int day,int x)	
          	:_n(1)
          	,_year(year)
          	,_month(month)
          	,_day(day)
          	,_ref(x)
          	,aa(1)
          {
          }
          

          初始化列表和构造函数共同定义了类对象的初始化行为。初始化列表提供了一种高效、直接初始化成员变量和基类的方式,而构造函数则完成剩余的初始化逻辑和设置,比如动态开辟一个数组进行赋值的时候,就用到函数体

          成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

          我们来看下面的代码:

          class A
          {
          public:
              A(int a)
                 :_a1(a)
                 ,_a2(_a1)
             {}
              
              void Print() {
                  cout
              A aa(1);
              aa.Print();
          }
          
          public:
              A(int a)
                 :_a1(a) // 现在_a1首先初始化
                 ,_a2(_a1) // 然后是_a2
              {}
              
              void Print() {
                  cout 
          public:
          	C(int x)
          		:_x(x)
          	{}
          private:
          	int _x;
          };
          int main()
          {
          	C cc1(1);
          	C cc2 = 2;
          	return 0;
          }
          
          public:
          	C(int x)
          		:_x(x)
          	{}
          private:
          	int _x;
          };
          
          public:
          	C(int x)
          		:_x(x)
          	{}
          	C(const C& cc)
          	{
          		cout 
          public:
          	C(int x)
          		:_x(x)
          	{}
          	
          private:
          	int _x;
          };
          int main()
          {
          	C& cc3 = 2;
          	return 0;
          }
          
          public:
          	void Push(const C& c)
          	{
          			//
          	}
          };
          
          public:
          	//explicit A(int a1, int a2)
          	A(int a1, int a2)
          		:_a1(a1)
          		,_a2(a2)
          	{}
          private:
          	int _a1;
          	int _a2;
          };
          int main()
          {
              A aa={1,2};
          	return 0;
          }
          
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]