C++中的类与对象深度解析 初始化列表引论123456789101112131415161718192021222324252627//初始化列表的引出classB{public:B(){cout 我是B的构造函数 endl;}private:int_b;};classA{public:A(){cout 我是A的构造函数 endl;}private:int_a;B b;};intmain(){A a;return0;}汇编验证初始化列表c推荐使用初始化列表进行初始化什么是初始化列表一个冒号开始以逗号分隔的数据成员列表每个成员变量后面放一个括号括号中放初始值或者表达式:_a(1),_aa(2)这个就是初始化列表12345678910111213141516171819//初始化列表使用democlassA{public:A():_a(1)//初始化列表, _aa(2){cout _a _aa endl;}private:int_a;int_aa;};intmain(){A a;return0;}存在自定义类型时初始化列表不写也认为有只是认为啊不写初始化列表会在函数体之前调用自定义类型的构造函数写了初始化列表是会进入函数体(花括号)然后调用具体的可以观察汇编成员变量只能在初始化列表里出现一次成员变量包含引用和const变量时必须在初始化列表里初始化引用和const变量必须初始化成员变量的声明次序就是初始化顺序与在初始化列表里先后顺序无关初始化列表是推荐使用的如果初始化列表不能解决问题混着用(在构造函数体内初始化)就行了explicit关键字引论1234567891011//int赋给对象democlassA{public:A(int){}};intmain(){A a 1;return0;}这么写是合法的赋值的过程发生了隐式类型转换前提是必须有A(int这样的构造函数)1234567891011//多个int赋给对象democlassA{public:A(int,int){}};intmain(){A a {1,2};return0;}C11支持多参数转换,C98不支持explicit关键字使用前面提到int可以赋给对象是隐式类型转换如果要禁止这种用法则用explicit修饰对应的构造函数1234567891011//explicit使用democlassA{public:explicitA(int){}};intmain(){A a 1;//errorreturn0;}static成员静态成员变量static修饰的成员变量静态成员函数static修饰的成员函数静态成员变量不是单单属于某一个对象的一个类创建的多个对象使用这个静态成员变量时使用的也是同一块内存即所有对象共有该静态成员变量一份内存多对象使用静态成员函数一般用来访问静态成员没有this指针由于没有this指针所以无法访问非静态的成员计算类的大小时不包括静态成员计算类的大小可以认为是计算对象的大小因为每个对象共有静态成员变量所以不能认为该变量特定属于某一个对象调用静态成员函数初始化静态成员变量12345678910111213141516171819//调用static函数和初始化static变量的democlass A{public:static int Print(){cout static int Print() endl;return _aa;}private:int _a;static int _aa;};int A::_aa 1;int main(){A::Print();return 0;}//调用static函数和初始化static变量的democlassA{public:staticintPrint(){cout static int Print() endl;return_aa;}private:int_a;staticint_aa;};intA::_aa 1;intmain(){A::Print();return0;}静态成员变量不能给缺省值必须在类外初始化因为在类外初始化时才分配空间所以不在类外初始化就不能用用了可能会导致链接错误静态成员函数不能调用非静态成员函数非静态成员函数可以调用静态成员函数普通静态函数需要通过this指针调用而静态成员函数没有this指针–百度待了解链接属性友元引论友元什么是友元友元是一种定义在类外部的普通函数或类但它需要在类体内进行说明为了与该类的成员函数加以区别在说明时前面加以关键字friend。–百度百科友元的作用突破封装12345678910111213141516171819classDate{friendbooloperator(Date d1, Date d2);private:int_year;int_month;int_day;};booloperator(Date d1,Date d2){returnd1._year d2._year d1._month d2._month d1._day d2._day;}intmain(){return0;}随笔记录编译器找一些声明只会往上找类的声明class A;如果我们在一个类内想访问另一个类的私有成员就需要友元类12345678910111213141516171819202122classTime{public:voidGetData(){cout d._year d._month d._day endl;}private:Date d;//借助这个对象};classDate{friendclassTime;private:int_year;int_month;int_day;};intmain(){return0;}友元突破类域内部类基础概念什么是内部类类里面定义一个类这就叫内部类内部类就是外部类的友元类所以内部类可以访问外部类的成员用法也和友元类很像计算类的大小时不算内部类内部类内可以直接访问外部类的静态成员不需要通过类名内部类受到类域影响和访问限定符限制内部类的使用1234567891011121314151617181920212223242526272829//内部类使用democlassA{public:classB{public:B(constA a){cout 我是内部类B endl;cout 我可以访问外部类A的变量_a:a._a endl;}private:int_b;};A(){}A(constB b){cout b._b endl;//error}private:int_a1;};intmain(){A a;A::B b(a);return0;}其实C不咋用内部类Java喜欢用内部类补充析构顺序例题类A、B、C、D问下面程序中析构函数的调用顺序12345678C c;intmain(){A a;B b;staticD d;return0;}答案析构顺序 B A D C构造顺序C A B D析构顺序是D B C A吗不是析构函数的调用时期对象声明周期结束后静态的变量存储在全局区main函数结束后会销毁栈帧①因为a,b都是局部对象先构造则后析构构造时是AB则析构肯定是BA换个角度理解栈的特点是先进后出那a先入栈就应该后销毁所以b先调用析构函数②剩下C DC是全局对象D是静态局部对象这两个谁先析构静态局部变量先析构全局变量C再析构D先析构C后析构即DC全局对象和静态局部对象的释放优先级在网上没有找到很好的解释个人理解CD都存在全局区所以CD的构造顺序和析构顺序应该是相反的即构造是CD则析构是DC组合①②得到BADC这种题的技巧把局部变量作为一组把全局和静态变量作为一组写出两个相应的构造顺序再逆置一下就得到相应的析构顺序又因为局部变量先析构再拼接两组的析构顺序得到答案可以把上面那段代码拷到编译器上然后自己写代码验证答案总结初始化列表提供了一种更好的初始化的方式如果初始化列表不能单独完成任务就结合构造函数体完成初始化任务explicit可以禁止内置类型和自定义类型的转换具体操作就是修饰对应的构造函数static成员可以牵扯出很多东西比如静态成员函数可不可以非静态变量等等抓住关键点静态成员函数没有this指针static成员变量始终是一块内存类外初始化才会分配空间友元主要解决了我们在类外不能访问私有成员变量的问题本质上破坏了封装不建议大量使用内部类C一般不怎么用内部类理解为外部类的友元同时受到访问限定符的限制类外使用内部类得用::突破类域限制面向对象是在模拟是在抽象模拟我们的现实世界