private访问限定符的限制

发布时间:2025-06-24 17:14:52  作者:北方职教升学中心  阅读量:595


但是友元会增加耦合度,破坏了封装,所以友元不宜多用。A、D,4个类的定义:

C c;intmain(){A a;B b;staticD d;//声明周期为全局,先析构局部变量,先定义的后析构,再析构全局变量return0}

程序中A,B,C,D构造函数调用顺序为:C、

  • 匿名对象生命周期只在当前一行,一般临时定义一个对象当前用一下即可,就可以定义匿名对象。private访问限定符的限制。

  • 每个成员变量在初始化列表中只能出现一次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。当前主流的相对新一点的编译器对于连续一个表达式步骤中的连续拷贝会进行合并优化,有些更新更"激进"的编译还会进行跨行跨表达式的合并优化。

  • #include<iostream>usingnamespacestd;classA{public://默认构造A(inta =0):_a1(a){cout <<"A(int a)"<<endl;}//拷贝构造A(constA&aa):_a1(aa._a1){cout <<"A(const A& aa)"<<endl;}//赋值运算符重载A&operator=(constA&aa){cout <<"A& operator=(const A& aa)"<<endl;if(this!=&aa){_a1 =aa._a1;}return*this;}A&operator++(){++_a1;return*this;}~A(){cout <<"~A()"<<endl;}voidPrint(){cout <<"Print()——>"<<_a1 <<endl;}private:int_a1 =1;};voidf1(A aa){}//传值传参voidmain1(){//隐式类型转换,连续的 构造+拷贝构造->优化为直接构造 A aa1 =1;//只是直接构造,无需优化constA&aa2 =1;//不连续的表达式不会优化A aa3(1);//构造f1(aa3);//拷贝构造,若用f1函数引用接收,就不会调用拷贝构造//隐式类型转换,连续的 构造+拷贝构造->优化为直接构造f1(1);f1(A(2));//匿名对象,连续的 构造+拷贝构造->优化为直接构造//总结:一个表达式中,连续的 构造+拷贝构造->优化为直接构造}/A f2(){//本质:先构造aa,由于函数时结束时销毁aa,所以再拷贝构造一个临时对象A aa(1);//构造++aa;returnaa;//返回拷贝构造的临时对象}A f3(){A aa(1);returnaa;}//传值返回voidmain2(){//将构造aa,拷贝构造临时对象——>优化为:直接构造临时对象(vs2022)f2().Print();cout <<"*****"<<endl <<endl;//连续的 构造+拷贝构造+拷贝构造->优化为:直接构造(vs2022)A ret =f3();ret.Print();cout <<"*****"<<endl <<endl;//以下编译器不做优化A ret1;ret1 =f3();//注意:这是赋值并非拷贝构造ret1.Print();cout <<"*****"<<endl <<endl;}intmain(){main1();main2();return0;}
    B、protected、

  • 如何优化C++标准并没有严格规定,各个编译器会根据情况自行处理。D、

  • 引用成员变量const成员变量没有默认构造的类类型变量,必须放在初始化列表位置进行初始化,否则会编译报错。如果你没有给缺省值,对于没有显示在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。

  • #include<iostream>usingnamespacestd;classA{// 友元声明 friendclassB;private:int_a1 =1;int_a2 =2;};classB{public:voidfunc1(constA&aa){cout <<aa._a1 <<endl;cout <<_b1 <<endl;}voidfunc2(constA&aa){cout <<aa._a2 <<endl;cout <<_b2 <<endl;}private:int_b1 =3;int_b2 =4;};intmain(){A aa;B bb;bb.func1(aa);bb.func2(aa);return0;}
    1. 友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元。

    2. 构造函数前面加explicit就不再支持隐式类型转换。

    #include<iostream>usingnamespacestd;classA{public:A(){++_scount;}A(constA&t){++_scount;}~A(){--_scount;}//静态成员函数:没有默认的this指针staticintGetACount(){// _a++; 由于没有this指针,无法操作非静态成员变量return_scount;}private:// 类里面声明 staticint_scount;int_a;};// 类外面初始化 intA::_scount =0;intmain(){//cout << A::_scount << endl; //若_scount访问权限为public,可以通过指定类域访问//cout << sizeof(A) << endl;  //1//指定类域调用静态成员函数cout <<A::GetACount()<<endl;//0A a1,a2;{A a3(a1);cout <<A::GetACount()<<endl;//3//该域结束a3就销毁了,调用析构函数}//两种方式调用静态成员:指定类域静态成员/对象.静态成员cout <<A::GetACount()<<endl;//2cout <<a1.GetACount()<<endl;//2return0;}

    设已经有A、C

    求1+2+3+…+n

    classSum{public:Sum(){_sum+=_i;_i++;}staticintGetSum(){return_sum;}private:staticint_i;staticint_sum;};intSum::_i =1;intSum::_sum =0;classSolution{public:intSum_Solution(intn){//Sum a[n];Sum*p =newSum[n];delete[]p;returnSum::GetSum();}};

    四.友元

    1. 友元提供了一种突破类访问限定符封装的方式,友元分为:友元函数友元类,在函数声明或者类声明的前面加friend,并且把友元声明放到⼀个类的里面。

    2. 内部类本质也是一种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了。对于没有显示在初始化列表初始化的自定义类型成员会调用这个成员类型的默认构造函数,如果没有默认构造会编译错误。

    3. 非静态的成员函数,可以访问任意的静态成员变量和静态成员函数。

    4. 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是C的友元。D
      程序中A,B,C,D析构函数调用顺序为:B、

    5. 尽量使用初始化列表初始化,因为不在初始化列表初始化的成员也会走初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化。

    #include<iostream>usingnamespacestd;classA{private:staticint_k;int_h =1;public:classB//B默认是A的友元:B可以访问A的私有成员{public:voidfunc(constA&a){cout <<_k <<endl;cout <<a._h <<endl;}private:int_b =1;};};intA::_k =1;intmain(){cout <<sizeof(A)<<endl;//4字节A::B b;//必须指定类域定义b,无法用B b;A aa;b.func(aa);return0;}

    求1+2+3+…+n

    classSolution{public:classSum{public:Sum(){sum+=i;i++;}};intSum_Solution(intn){//Sum a[n];Sum*a =newSum[n];delete[]a;returnsum;}private:staticinti;staticintsum;};intSolution::i =1;intSolution::sum =0;

    六.匿名对象

    1. 类型(实参)定义出来的对象叫做匿名对象,相比之前我们定义的类型 对象名(实参)定义出来的叫有名对象。

    2. 一个函数可以是多个类的友元函数。

    五.内部类

    1. 如果一个类定义在另一个类的内部,这个类就叫做内部类。

    2. 内部类默认是外部类的友元类。

    3. 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。

    4. 用static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。内部类是一个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。C、

    5. C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。

    6. 初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的的先后顺序无关。

      类和对象

      • 一.初始化列表
        • 面试题
      • 二.隐式类型转换与explicit
      • 三.静态成员——static
      • 四.友元
      • 五.内部类
      • 六.匿名对象
      • 七.对象拷贝时的编译器优化

      一.初始化列表

      1. 之前我们实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式,就是初始化列表,初始化列表的使用方式是以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。B、

      2. 外部友元函数可访问类的私有和保护成员但是不允许修改,友元函数仅仅是⼀种声明,他不是类的成员函数。建议声明顺序和初始化列表顺序保持一致。

      #include<iostream>usingnamespacestd;// 前置声明,都则A的友元函数声明编译器不认识B classB;classA{// 友元声明 friendvoidfunc(constA&aa,constB&bb);private:int_a1 =1;int_a2 =2;};classB{// 友元声明 friendvoidfunc(constA&aa,constB&bb);private:int_b1 =3;int_b2 =4;};voidfunc(constA&aa,constB&bb){cout <<aa._a1 <<endl;cout <<bb._b1 <<endl;}intmain(){A aa;B bb;func(aa,bb);return0;}
      1. 友元类中的成员函数都可以是另一个类的友元函数,都可以访问另一个类中的私有和保护成员。

      2. 突破类域就可以访问静态成员,可以通过类名::静态成员或者对象.静态成员来访问静态成员变量和静态成员函数。

      3. 静态成员函数中可以访问其他的静态成员,但是不能访问非静态的,因为没有this指针。

      4. 静态成员也是类的成员,受public、

      5. 有时提供了便利。

      #include<iostream>#include<algorithm>//算法的头文件usingnamespacestd;classA{public:A(inta =0):_a(a){cout <<"A(int a)"<<endl;}~A(){cout <<"~A()"<<endl;}private:int_a;};classSolution{public:intSum_Solution(intn){//...returnn;}};boolmyfunction(inti,intj){returni >j;}intmain(){A aa1;//有名对象// A aa2(); 错误:无法区分函数声明与定义对象// 匿名对象的生命周期为当前一行A();//匿名对象A(1);Solution st;cout <<st.Sum_Solution(10)<<endl;//这样更方便cout <<Solution().Sum_Solution(10)<<endl;inta[]={5,3,6,9,8,4,2,1,7};//升序<sort(a,a +9);//降序>sort(a,a +9,myfunction);greater<int>gt;sort(a,a +9,gt);sort(a,a +9,greater<int>());//匿名对象return0;}

      七.对象拷贝时的编译器优化

      了解就行:

      1. 现代编译器会为了尽可能提高程序的效率,在不影响正确性的情况下会尽可能减少一些传参和传返回值过程中可以省略的拷贝。

      2. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。A、

      3. 静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表。

      #include<iostream>usingnamespacestd;classTime{public:// 默认构造Time(inthour =0):_hour(hour){cout <<"Time()"<<endl;}private:int_hour;};classDate{public:Date(int&xx,intyear,intmonth,intday):_year(year),_month(month),_day(day),_ptr((int*)malloc(12)),_n(100),_ref(xx),_t(1)//初始化列表:成员变量定义的地方{//初始化列表与函数体可以配合使用if(_ptr ==nullptr){perror("malloc fail!");}else{memset(_ptr,0,12);}}voidPrint()const{cout <<_year <<"/"<<_month <<"/"<<_day <<endl;}private:// 声明未开空间 可以在函数内部初始化,也可以在初始化列表中初始化int_year =1;//C++11 中的缺省值——>初始化列表用的int_month;int_day;int*_ptr;// 必须在定义的地方(初始化列表)中初始化constint_n;int&_ref;Time _t;//即使初始化列表没有_t,也会调用Time的默认构造};intmain(){intxx =200;//对象定义,对象中的成员在初始化列表中定义Date d1(xx,2024,7,20);d1.Print();return0;}

      在这里插入图片描述

      面试题

      在这里插入图片描述

      #include<iostream>usingnamespacestd;classA{public:A(inta):_a1(a),_a2(_a1){}voidPrint(){cout <<_a1 <<" "<<_a2 <<endl;}private:int_a2 =2;//先声明的先在初始化列表中定义,由于_a1是随机值,所以_a2就是随机值int_a1 =2;//再就是实参1传给_a1,_a1就是1};intmain(){A aa(1);aa.Print();//打印 1 随机值return0;}

      有一个类A,其数据成员如下: 则构造函数中,成员变量一定要通过初始化列表来初始化的是:bc

      classA{private:inta;public:constintb;float*&c;staticconstchar*d;//静态成员类内声明,类外初始化staticdouble*e;};

      二.隐式类型转换与explicit

      1. C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。每个构造函数都有初始化列表

      #include<iostream>usingnamespacestd;classA{public://构造函数explicit就不再支持隐式类型转换 //explicit A(int a1)A(inta1){_a1 =a1;}//explicit A(int a1, int a2)A(inta1,inta2){_a1 =a1;_a2 =a2;}A(constA&a){_a1 =a._a1;_a2 =a._a2;}voidPrint(){cout <<_a1 <<" "<<_a2 <<endl;}private:int_a1;int_a2;};intmain(){A a1(1);// 调用有参构造函数a1.Print();//单参数构造函数支持:隐式类型转换//2构造一个A的临时对象,再用这个临时对象拷贝构造a2//编译器遇到:构造+拷贝构造——>优化为:直接构造A a2 =2;a2.Print();inti =1;doubled =i;//const修饰引用A&ra1 =a1;//A& ra1 = 2; 权限放大:临时对象具有常性constA&ra1 =2;//构造临时对象,但不存在拷贝构造(引用)inti =1;doubled =i;//double& rd = i; 权限放大:临时对象具有常性constdouble&rd =i;return0;}

      在这里插入图片描述
      在这里插入图片描述

      #include<iostream>usingnamespacestd;classA{public:A(inta1 =0){_a1 =a1;}voidPrint(){cout <<_a1 <<endl;}private:int_a1;};classStack{public:voidPush(constA&a){//...}private:A _arr[10];int_top;};intmain(){Stack st;A a1(1);st.Push(a1);//直接传入常量st.Push(3);return0;}

      在这里插入图片描述

      #include<iostream>usingnamespacestd;classA{public:A(inta1 =0,inta2 =0):_a1(a1),_a2(a2){}voidPrint(){cout <<_a1 <<endl;}private:int_a1;int_a2;};classStack{public:voidPush(constA&a){//...}private:A _arr[10];int_top;};intmain(){Stack st;//C++11支持传入多个参数进行隐式类型转换A a1 ={1,1};A&ra1 =a1;st.Push(ra1);//等价于st.Push({1,1});//A& ra1 = { 2,2 }; errorconstA&ra1 ={2,2};return0;}

      三.静态成员——static

      1. 用static修饰的成员变量,称之为静态成员变量,静态成员变量一定要在类外进行初始化。