网站+建设设计企业公司

当前位置: 首页 > news >正文

网站+建设设计,企业公司,保定seo网站排名,网页布局的设计原则#x1f911;个人主页: 起名字真南 #x1f911;个人专栏:【数据结构初阶】 【C语言】 【C】 目录 1 深入构造函数2 类型转换3 static成员4 友元函数5 内部类6 匿名对象 1 深入构造函数 之前我们实现构造函数的时候#xff0c;初始化成员变量都是在函数体内赋值#xff0c…个人主页: 起名字真南 个人专栏:【数据结构初阶】 【C语言】 【C】 目录 1 深入构造函数2 类型转换3 static成员4 友元函数5 内部类6 匿名对象 1 深入构造函数 之前我们实现构造函数的时候初始化成员变量都是在函数体内赋值构造函数初始化还有另一个方式就是初始化列表初始化列表的使用方式是从一个冒号开始成员变量之间用‘ ’逗号分隔开每个成员变量的后面都有一个括号里面存放着初始化的值或表达式。每个成员变量都只能在初始化列表中出现一次可以理解为是每个成员变量进行定义初始化的地方。引用成员变量const成员变量没有默认构造的类类型成员变量必须放在初始化列表的地方进行初始化否则会编译报错C11支持在成员变量声明的地方给缺省值这个缺省值目的是给没有显示在初始化列表初始化的变量使用的。使用初始化列表进行初始化因为即便没有在初始化列表进行初始化编译器同样会经过初始化列表如果在变量定义的时候给了缺省值那么就会用缺省值进行初始化如果没有缺省值就会按照括号里的值或表达式进行初始化对于没有在初始化列表显示的内置类型是否进行初始化却决于编译器而对于自定义类型则会调用他的默认构造函数如果没有默认构造就会造成编译报错。初始化列表的初始化顺序与该成员变量在初始化列表中的顺序无关至于这个变量的声明顺序有关先声明的先初始化。 总结 无论是否写初始化列表每个构造函数都有初始化列表。 无论是否在初始化列表显示初始化每个成员变量都会走一遍初始化列表。 #includeiostream using namespace std;class Time { public:Time(int hour):_hour(hour){cout Time() endl;} private:int _hour; }; class Date { public:Date(int x, int year 1, int month 1, int day 1):_year(year), _month(month), _day(day), _t(12), _ret(x), _n(1){//只能在初始化列表初始化不能再函数体内进行初始化//_ret x;//_t 12;//_n 1;}void Print(){cout _year - _month - _day endl;} private:int _year;int _month;int _day;// 以下变量能且只能在初始化列表进行初始化Time _t; //类类型成员变量 没有默认构造int _ret; //引用成员变量 const int _n; //const类型成员变量 }; int main() {int i 0;Date d1(i);d1.Print();return 0; }运行结果如下 虽然Time类型的成员变量都是内置类型成员变量并且在初始化的时候可以不写默认构造但是由于在Time中已经写了一个构造函数所以不会生成默认构造而在Date类中作为了自定义类类型的成员变量如果没有在初始化列表中初始化就会调用他的默认构造因为它没有默认构造就会报错。 如果把初始化列表中的Time删除就会出现下面的错误
class Time { public:Time(int hour):_hour(hour){cout Time() endl;} private:int _hour; }; class Date { public:Date():_month(1){cout Date() endl;}void Print(){cout _year - _month - _day endl;} private:int _year 1;int _month 1;int _day;// 注意这里不是初始化而是给初始化列表提供了缺省值//如果初始化列表没有显示初始化就是用这个缺省值初始化Time _t 1; int* _ret (int*)malloc(sizeof(int) * 3); const int _n 1; }; int main() {Date d1;d1.Print();return 0; }运行结果如下
2 类型转换 C支持内置类型隐式类型转换为类类型对象需要有相关内置类型作为参数的构造函数构造函数前面加上explicit就不再支持隐式类型转换类类型对象之间也可以隐式类型转换需要相对应的构造函数支持 #includeiostream using namespace std;class A { public://构造函数explicit就不再支持隐式类型转换// explicit A(int a1)A(int a1):_a1(a1){}A(int a1, int a2):_a1(a1),_a2(a2){}void print(){cout _a1 _a2 endl;}int get() const{return _a1 _a2;} private:int _a1 1;int _a2 2; }; class B { public:B(const A a):_b(a.get()){} private:int _b 0; }; int main() {A aa1 1;aa1.print();const A aa2 1;//多参数传参用大括号A aa3 { 3, 3 };aa3.print();cout aa3.get() endl;//A 类型 隐式转换为 B类型B b aa3;const B rb aa3;return 0; }3 static成员 用static修饰的成员变量叫做静态成员变量必须要在类外进行初始化。静态成员变量为所有类对象共享不属于某个具体的对象不存在对象中存放在静态区中。用static修饰的成员函数称为静态成员函数静态成员函数没有this指针。静态成员函数中可以访问其他的静态成员但是不能访问非静态成员因为没有this指针。非静态成员函数可以访问任意的静态成员变量和静态成员函数突破类域就可以访问静态成员可以通过类名静态成员对象.静态成员来访问静态成员变量和静态成员函数。静态成员也受publicprivateprotected等访问限定符限制。静态成员函数不能在声明的位置给缺省值进行初始化因为缺省值是给构造函数初始化列表使用的静态成员不属于某个对象不走初始化列表。 #includeiostream using namespace std;class A { public:A(){_scount;};A(const A t){_scount;}~A(){–_scount;}static int GetCount(){return _scount;} private://类里面声明static int _scount; };//类外面初始化 int A::_scount 0;int main() {cout A::GetCount() endl;A a1, a2;cout A::GetCount() endl;A a3(a1);cout A::GetCount() endl;cout a3.GetCount() endl;return 0; }运行结果 第一次输出的结果是0是因为我们在初始化的时候初始化的值为0然后在每一次调用构造函数的时候就会加1调用析构的时候减1我们可以看到构造了a1a2两个变量所以调用了两次然后在使用拷贝构造a3调用构造函数在所以这个时候的count是3每次调用构造函数都会然后最后函数销毁时会自动调用析构函数调用三次。 4 友元函数 友元提供了一种突破类域访问限制的方法友元分为友元函数友元类在函数声明和类声明前面加上friend并且把友元声明放到一个类里面。外部友元函数可以访问内部类的私有和保护变量友元函数仅仅是一种声明并不是类的成员函数。友元函数可以在类定义的任何地方声明不受访问限定符的限制。一个函数可以是多个类的友元函数友元类的关系是单向的并不是双向的比如A是B的友元但是B不是A的友元友元的关系不能传递比如A是B的友元B是C的友元但A不是C的友元容易破坏封装不宜多用 #includeiostream using namespace std;class A; //前置声明为了调用函数的时候可以找到A类 class B {friend void func(const A aa, const B bb);private:int _b1 1;int _b2 2; };class A {friend void func(const A aa, const B bb);private:int _a1 1;int _a2 2; };void func(const A aa, const B bb) {cout aa._a1 endl;cout bb._b1 endl; } int main() {A a1, a2;B b1, b2;func(a1, b1);return 0; }在写上面的代码我们需要注意一个情况就是关于前置声明因为编译器只会向上查找在B类中的友元函数用到了A类所以我们需要在B类的前面提前声明A类告诉编译器A类存在。 class C {friend class D; private:int _c1 1;int _c2 2; };class D { public:void func01(const C cc){cout cc._c1 endl;cout _d1 endl;}void func02(const C cc){cout cc._c2 endl;cout _d2 endl;}private:int _d1 3;int _d2 4; };int main() {C cc;D dd;dd.func01(cc);dd.func02(cc);return 0; }5 内部类 如果一个类定义在一个类的内部那么这个内部的类就叫做内部类内部类是一个独立的类跟定义在全局相比他只受外部类的类域和访问限定符限制所以外部类定义的对象中不包含内部类。内部类默认是外部类的友元内部类本质上也是一种封装如果A类和B类有紧密的联系并且A类设计出来是专门为B类使用的那么就可以把B类设计为A类的内部类B作为内部类可以访问A类的私有成员变量。 class AA { public:class BB{public:void func01(const AA aa){cout _k endl;cout aa._x endl;}}; private:static int _k;int _x 1; };int AA:: _k 2;int main() {cout sizeof(AA) endl;AA aa;AA::BB bb;bb.func01(aa);return 0; }结果展示 这里sizeof的大小是4的原因是_k是在静态区不算做A类里面 6 匿名对象 用类型实参定义出来的对象叫做匿名对象用类型 对象名 定义出来的对象叫做有名对象匿名对象的生命周期只在当前一行。 class AAA { public:AAA(int a 0):_a(a){cout AAA(int a) endl;}~AAA(){cout ~AAA() endl;} private:int _a; }; class Solution { public:int Sum_Solution(int n) {//…return n;} }; int main() {//匿名对象的定义AAA();AAA(1);//有名对象AAA a2(2);Solution().Sum_Solution(10);return 0; }运行结果 这里分别调用了三次构造三次析构证明对象确实存在生命周期只存在一行在下一个对象创建之后就已经销毁调用了析构