小工具知识网

当前位置: 首页 > 行业知识 > 【C++】初始化列表、static成员、友元、匿名对象、附练习题

行业知识

【C++】初始化列表、static成员、友元、匿名对象、附练习题

2026-10-21 12:57:52 来源:互联网转载

文章目录

    • 前言
    • 一、构造函数【初始化列表】
      • 1.1 构造函数体赋值
      • 1.2 初始化列表
      • 1.3 explicit关键字
      • 二、static成员
        • 2.1 概念
        • 2.2 特性
        • 三、友元
          • 3.1 友元函数
          • 3.2 内部类
          • 四、匿名对象
            • 4.1 拷贝对象时的一些编译器优化
            • 五、再次理解类和对象
            • 六、练习题
              • 6.1 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句
              • 6.2 计算日期到天数的转换
              • 6.3 日期差值
              • 6.4 打印日期
              • 6.5 ���加天数

                前言

                我们前面学习了关于类和对象的6个默认成员函数,知道了一个空类中有构造函数和析构函数,通过对对象初始化和对象中进行资源清理,达到初始化和销毁的作用。我们再对一些小的点进行补充,看看类和对象的一些细节。

                一、构造函数【初始化列表】

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

                      【注意】

                      1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
                      2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
                        • 引用成员变量
                        • const成员变量
                        • 自定义类型成员(且该类没有默认构造函数时)
                      class A{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};
                      • const和引用必须走初始化列表
                      • 自定义类型,如果没有默认构造函数就会报错,我们需要进行显示调用【()里面是参数】
                        1. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
                        class Time{public:Time(int hour = 0):_hour(hour){cout public:Date(int day){}private:int _day;Time _t;};int main(){Date d(1);}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){}/*// 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:A() { ++_scount; }A(const A& t) {++_scount; }~A() {--_scount; }static int GetACount() { return _scount; }private:static int _scount;};// 放在外面进行初始化int A::_scount = 0;void main(){cout public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}// d1 _cout friend ostream& operator}private:int _year;int _month;int _day;};ostream& operator_cout _cin  d._year;_cin  d._month;_cin  d._day;return _cin;}int main(){Date d;cin  d;cout private:static int k;int h;public:class B // B天生就是A的友元{public:void foo(const A& a){cout A::B b;b.foo(A());return 0;}public:A(int a = 0):_a(a){cout cout public:int Sum_Solution(int n) {//...return n;}};int main(){A aa1;// 不能这么定义对象,因为编译器无法识别下面是一个函数声明,还是对象定义//A aa1();// 但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,// 但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数A();A aa2(2);// 匿名对象在这样场景下就很好用,当然还有一些其他使用场景,这个我们以后遇到了再说Solution().Sum_Solution(10);return 0;}public:A(int a = 0):_a(a){cout cout cout _a = aa._a;}return *this;}~A(){cout }A f2(){A aa;return aa;}int main(){// 传值传参A aa1;f1(aa1);cout     class Sum {      public:        Sum() {            _ret += _i;            _i++;        }        static int GetRet() {            return _ret;        }    };  public:    // sum是Solution的友元    int Sum_Solution(int n) {        Sum a[n];        return _ret;    }  private:    static int _i;    static int _ret;};int Solution::_i = 1;int Solution::_ret = 0;    int year, mon, day;    int data[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};    while (cin  year  mon  day) {        int sum = 0;        for (int i = 1; i             sum += data[i];        }        if ((mon == 2) && ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0))) {            // 如果是闰年就要多加1天            sum = sum + 1 + day;        }        else {            // 需要加上最后的天数            sum = sum +day;        }        cout 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};//给出年月日,计算距离0000年0月1日的天数和int CountDay(int y, int m, int d){    // 计算0-y年的天数    int yearDay = y * 365 + y / 4 - y / 100 + y / 400;    // 计算到0-m月的天数    int monthDay = mon[m - 1];    if (m  2 && ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0))        monthDay += 1;    return yearDay + monthDay + d;}int main() {    int year1, month1, day1;    scanf("%4d%2d%2d", &year1, &month1, &day1);    int n1 = CountDay(year1, month1, day1);    int year2, month2, day2;    scanf("%4d%2d%2d", &year2, &month2, &day2);    int n2 = CountDay(year2, month2, day2);    cout     int year;    int day;    int mon[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};    while (cin  year  day) {        if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0))            mon[2] = 29;        else            mon[2] = 28;        for (int i = 1; i             if (day                 printf("%04d-%02d-%02d\n", year, i, day);                break;            } else {                day -= mon[i];            }        }    }}    int m = 0;    while (cin  m) {        int year, mon, day, num;        for (int i = 0; i 

上一篇:暗黑不朽怎么进亚太服务器?

下一篇:易语言实现自动下载功能教程,轻松掌握下载自动化技巧