【C++】类与对象—— 初始化列表 、static 静态成员、

小明 2025-04-30 02:01:59 4

类与对象

  • 1 再谈构造函数
    • 1.1 构造函数体赋值
    • 1.2 初始化列表
      • 语法:
      • 建议:
      • 初始化顺序:
      • 注意:
      • 1.3 explicit关键字
      • 2 static 静态成员
        • 2.1 概念
        • 2.2 声明成员变量
        • 2.3 使用类的静态成员
        • 2.4 定义静态成员
        • 总结
        • Thanks♪(・ω・)ノ谢谢阅读!!!
        • 下一���文章见!!!

          1 再谈构造函数

          1.1 构造函数体赋值

          在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值,以我们之前实现的Date类对象为例。

          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;
          };
          

          建议:

          有时我们可以忽略数据成员初始化的和赋值之间的差异,但并非总是这样。

          如果成员是const 或 引用变量的话,必须将其初始化。类似的如果存在自定义类型并且该类不存在构造函数时,也必须将其初始化。例如:

          class A {
          private:
          	int a;
          };
          class Date
          {
          public:
          	Date(int year, int month, int day)
          	{
          		_year = year;
          		_month = month;
          		_day = day;
          		
          	}
          private:
          	const int _year;
          	int& _month;
          	int _day;
          	A a;
          };
          int main(){
          	const Date a1(2024,2,24);
          	return 0;
          }
          

          来看看报错:

          显然我们需要初始化来帮助我们解决这些问题。

          在很多类中初始化和赋值的区别事关底层效率的问题:前者直接初始化数据成员,后者则先初始化再赋值。除了效率问题外更重要的是,一些数据成员必须初始化。所以一般建议养成使用初始化列表的习惯,这样可以避免某些意想不到的编译错误,特别是遇到类包含构造函数初始值的成员时。

          初始化顺序:

          显然在构造函数中每个成员只能出现一次。否则给同一个成员赋两个不同初始值有什么意义呢?

          需要注意的是初始化列表不限定初始化的执行顺序,因为成员初始化的顺序与他们在类出现顺序一致,第一个成员先初始化,然后第二个,以此类推,因此构造函数初始化列表的前后位置并不影响实际的初始化顺序。

          但是下面这个例子不同:

          class A
          {
          public:
          	A(int a)
          		:_a1(a)
          		,_a2(_a1)
          	{}
          	void Print() {
          		cout 
          	A aa(1);
          	aa.Print();
          }
          
          public:
          // 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
          // explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译
             explicit Date(int year)
             	:_year(year)
             	{}
          private:
             int _year;
             int _month;
             int _day;
          };
          void Test()
          {
             	Date d1(2022);
             // 用一个整形变量给日期类型对象赋值
             // 实际编译器背后会用2023构造一个无名对象,
             //最后用无名对象给d1对象进行赋值
          }
          
          public:
          // 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修饰构造函数,
          //禁止了单参构造函数类型转换的作用
          }
          
          public:
          	Date(int year, int month, int day)
          	:_year(year)
          	,_month(month)
          	,_day(day)
          	{ }
          static void count();
          private:
          	int _year;
          	int _month;
          	int _day;
          };
          void count(){
          };
          int main(){
          	Date d1;
          	Date* d2 = &d1; 
          	d2-count();
          	d1.count();
          	return 0;
          }
          
The End
微信