C++奇迹之旅:初始化列表与explicit

慈云数据 2024-05-11 技术支持 51 0

请添加图片描述

文章目录

  • 📝再谈构造函数
  • 🌠 构造函数体赋值
    • 🌉初始化列表
    • 🌉初始化列表效率
      • 🌠隐式类型转换
      • 🌉复制初始化
      • 🌠单多参数构造函数
        • 🌉explicit关键字
        • 🚩总结

          📝再谈构造函数

          🌠 构造函数体赋值

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

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

          虽然上面构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,这和我们之间常常说的给缺省值其实就是赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。

          🌉初始化列表

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

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

          为什么要有初始化列表来赋初值,不能直接给缺省值,或者传参吗?

          class Date
          {
          public:
          	Date(int year, int month, int day)
          	{
          		_year = year;
          		_month = month;
          		_day = day;
          		_x = 1;
          	}
          private:
          	int _year;
          	int _month;
          	int _day;
          	//必须在定义初始化
          	const int _x;
          };
          

          由于const必须在定义时就要进行初始化,而这个在构造函数中_x=1的行为是赋值行为,不是初始化,因此const 修饰_x无法再赋值。引用&也是如此,需要在定义的时候并且进行初始化,不能分开。

          在这里插入图片描述

          因此对于普通的内置类型,普通成员变量都可以在函数体或者在初始化列表进行初始化,

          int _year;
          int _month;
          int _day;
          

          因为在这里只是声明,没有定义,定义时实例化的时候完成的,而有些特殊的成员变量需要再定义的时候就初始化,而不是再通过赋值。

          class Date
          {
          public:
              Date(int year, int month, int day, int& refDay)
                  : ref(refDay)
                  , _x(1)
              {
                  _year = year;
                  _month = month;
                  _day = day;
              }
              void printDate()
              {
                  std::cout 
              int someDay = 22;
              Date date1(2024, 4, 22, someDay);
              date1.printDate();
              return 0;
          }
          
          public:
          	A(int a)
          		:_a(a)
          	{}
          private:
          	int _a;
          };
          class B
          {
          public:
          	B(int a, int ref)
          		:_aobj(a)
          		, _ref(ref)
          		, _n(10)
          	{};
          private:
          	A _aobj;     // 没有默认构造函数
          	int& _ref;   //引用
          	const int _n;//const
          };
          int main()
          {
          	int x = 10;
          	B bb(20, x);
          	return 0;
          }
          
          public:
              Date(int year, int month, int day, int& refDay)
                  : ref(refDay)
                  , _x(1)
              {
                  _year = year;
                  _month = month;
                  _day = day;
              }
          private:
              int _year;
              int _month;
              int _day;
              int& ref;
              const int _x;
          };
          
          public:
          	Stack(size_t capacity = 4)
          	{
          		_array = (DataType*)malloc(sizeof(DataType) * capacity);
          		if (NULL == _array)
          		{
          			perror("malloc申请空间失败!!!");
          			return;
          		}
          		_capacity = capacity;
          		_size = 0;
          	}
          	void Push(DataType data)
          	{
          		// CheckCapacity();
          		_array[_size] = data;
          		_size++;
          	}
          	// 其他方法...
          	~Stack()
          	{
          		if (_array)
          		{
          			free(_array);
          			_array = NULL;
          			_capacity = 0;
          			_size = 0;
          		}
          	}
          private:
          	DataType* _array;
          	int _capacity;
          	int _size;
          };
          class MyQueue
          {
          public:
          	// 初始化列表,不管你写不写,每个成员变量都会先走一遍
          	// 自定义类型的成员会调用默认构造(没有默认构造就编译报错)
          	// 内置类型有缺省值用缺省值,没有的话,不确定,要看编译器,有的编译器会处理,有的不会处理
          	// 先走初始化列表 + 再走函数体
          	// 实践中:尽可能使用初始化列表初始化,不方便再使用函数体初始化
          	MyQueue()
          		:_size(1)
          		, _ptr((int*)malloc(40))
          	{
          		memset(_ptr, 0, 40);
          	}
          private:
          	// 声明
          	Stack _pushst;
          	Stack _popst;
          	// 缺省值  给初始化列表用的
          	int _size = 0;
          	const int _x = 10;
          	int* _ptr;
          };
          int main()
          {
          	MyQueue q;
          	return 0;
          }
          
          public:
          	A(int a)
          		:_a1(a)
          		,_a2(_a1)
          	{}
          	void Print()
          	{
          		cout 
          	A aa(1);
          	aa.Print();
          }
          A. 输出1 1
          B.程序崩溃
          C.编译不通过
          D.输出1 随机值
          
          public:
          	A(int a)
          		:_a1(a)
          		,_a2(_a1)
          	{}
          	void Print()
          	{
          		cout 
          	A aa(1);
          	aa.Print();
          }
          
          	//...
          	A(); //默认构造函数
          	A(const A& d); //拷贝构造函数
          	A& operator=(const A& d); //赋值函数
          };
          class B
          {
          public:
          	B(const A& a); //B的成员对象
          private:
          	A m_a;     //成员对象
          };
          
          	...
          }
          
          	m_a = a;
          	...
          }
          
          public:
          	A(int a)
          		:_a(a)
          	{
          		cout 
          	A aa1(1);
          	//拷贝构造
          	A aa2 = aa1;
          	A aa3 = 3;
          	return 0;
          }
          
          public:
          	A(int a)
          		:_a(a)
          	{
          		cout 
          		cout 
          	A aa1(1);
          	A aa3 = 3;
          	return 0;
          }
          
          public:
          	A(int a)
          		:_a(a)
          	{
          		cout 
          	A& raa = 3;
          	return 0;
          }
          
          public:
          	void Push(const A& aa)
          	{
          		//...
          	}
          	//...
          };
          int main()
          {
          	Stack st;
          	A a1(1);
          	st.Push(a1);
          	A a2(2);
          	st.Push(a2);
          	//可以直接写
          	st.Push(2);
          	st.Push(4);
          	return 0;
          }
          
          	list}
          A aaa1(1, 2);
          A aaa2 = { 1, 2 };
          const A& aaa3 = { 1, 2 };
          
          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修饰构造函数,禁止了单参构造函数类型转换的作
          	用
          }
          
微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon