建设部网站打不开,c#网站开发网易云课堂百度云下载,怎么做网站营销,吐鲁番大型网站建设平台目录
前言
初始化列表#xff1a;
使用及特点#xff1a;
总结#xff1a;
案例分析#xff1a;
类型转换
单参数构造函数#xff1a;
多参数构造函数#xff1a;
static成员
友元
内部类
匿名对象
特点
使用方法#xff1a;
匿名对象使用实例补充#…目录
前言
初始化列表
使用及特点
总结
案例分析
类型转换
单参数构造函数
多参数构造函数
static成员
友元
内部类
匿名对象
特点
使用方法
匿名对象使用实例补充
对象拷贝时的编译器优化
后记 前言
欢迎大家来到小鸥的博客本篇将带你了解构造函数的初始化列表构造函数传参时的类型转换static成员友元内部类以及匿名对象等相关内容~ 初始化列表
在前面学习的构造函数实现中初始化成员变量时使用的都是在函数体内进行赋值的方法而构造函数还可以通过初始化列表来进行成员变量的初始化。
使用及特点
1. 初始化列表在函数参数列表后以一个冒号开始接着以逗号为分割每个成员变量后面跟一括号来放初始值或者表达式 //Date(int year, int month, int day)Date(int year 1, int month 1, int day 1):_year(year)//(year 1),_month(month),_day(day){}其中初始化列表的括号中可以是一个表达式
2. 每个成员变量在初始化列表中只能出现一次这是因为初始化列表的性质可以认为是成员变量定义初始化的地方就和函数的声明和定义一样定义有且只有一个。 3. 引用成员变量const成员变量没有默认构造的类类型成员变量都必须放在初始化列表中进行初始化否则将会报错 原因 引用在定义时必须指定引用对象类似指针必须指定指向的地址const修饰的变量必须在定义时赋值后续也不能通过赋值来修改const修饰具有常性类类型的成员变量定义时会调用默认构造函数若只存在普通构造函数又不给参数的话其定义就会报错但初始化列表中给它初始值之后就相当于调用了该类的普通构造函数传参 例 此处的i 和a 就是引用和const成员变量由于初始化列表的性质类似与定义所以可以在初始化列表中修改而不能在函数体中进行修改。
4. C11后支持在成员变量声明的位置给缺省值这个缺省值就是为了在当一个成员变量没有显示在初始化列表中时使用。 此时_day成员没有在初始化列表中也没有在函数体中进行赋值所以d1对象定义完成后得到的_day结果为2. 注意 成员变量声明时的值是一个缺省值而不是赋值即只有既不在初始化列表中也不在函数体中时才会使用和函数的缺省参数性质一样。成员变量声明处的缺省值和构造函数参数中的缺省值要注意区分前者是未显示在初始化列表中时使用而后者是为了构造函数没有传参时使用的。 5. 初始化列表中是按照声明时的顺序进行初始化因为开空间时的存放顺序就是按照声明的顺序存放的的和成员在初始化列表中的先后顺序无关但建议保持一致。 总结 尽量不在函数体中赋值 每个构造函数都有初始化列表 每个成员变量都会进行初始化列表 显示写在初始化列表中的成员直接进行初始化 不显示写在初始化列表中的成员 声明时有缺省值就用缺省值 没有缺省值 内置类型成员变量不确定看编译器大概率为随机值自定义类型成员变量调用它的默认构造没有则报错 引用const修饰没有默认构造的类类型成员变量必须显示写在初始化列表中进行初始化。 案例分析 结果分析 由声明顺序可知_b先声明所以先初始化但由于此时_a还未进行初始化所以_b初始化结果为零_a初始化使用传值参数a的值进行初始化所以结果为1综合可知声明时成员变量的缺省值只有在对其自身初始化时起作用_a在作为初始值为_b初始化时还未进行初始化所以_b结果为随机值而不是_a的缺省值 类型转换
C支持内置类型隐式转换为类类型对象但要保证自定义类型兼容该内置类型且类类型中存在兼容该内置类型的构造函数。
在构造函数前加上关键字explicit可以禁止该类型转换
单参数构造函数
class A
{
public:void Print(){cout _a endl;}A(int i 0):_a(i){}//拷贝构造函数A(const A pa):_a(pa._a){}
private:int _a;
};class Stack
{
public:void Push(const A a){//....}
private:A _arr[10];int top;
};int main()
{A aa1(1);//传参给构造函数进行正常构造aa1.Print();A aa3 aa1;//调用拷贝构造// 隐式类型转换// 2先隐式转换为double构造出一个A类型的临时对象再将临时对象拷贝构造到aa2// 编译器中遇到构造拷贝构造-优化为直接构造A aa2 2;aa2.Print();//A raa2 aa2;//引用//const A raa3 2;//2类型转换产生临时变量具有常性所以必须加上const才能引用Stack st;st.Push(aa1);st.Push(3);//int类型转换为A类型return 0;
}
上述代码中构造函数加上explicit 多参数构造函数
class A
{
public:A(int a 1, int b 1):_a(a), _b(b){}private:int _a;int _b;
};
class Stack
{
public:void Push(const A a){//....}
private:A _arr[10];int top;
};
int main()
{A aa1(2, 2);A aa2 { 2,2 };Stack st1;st1.Push(aa1);st1.Push({ 2,2 });return 0;
}
参数为多个时类型转换要用大括号括起来。
总结C支持隐式类型转换是借助构造函数来进行的。
static成员
1. static修饰的成员变量称为静态成员变量静态成员变量必须在类外进行初始化 2. 静态成员变量是该类的所有对象共享的不单独属于某个对象也不存在对象中而是存在静态区中所有对象都可以调用 3. static修饰成员函数叫做静态成员函数静态成员函数不存在this指针
4. 静态成员函数只能访问其他静态成员函数由于没有this指针所以不能访问非静态成员变量 5. 非静态成员函数可以随意访问静态成员变量和函数
6. 静态成员也受publicprivateprotected访问限定符的限制
7. 静态成员为public时可通过 类名::静态成员 和 对象名::静态成员 两种方式来外部访问 8. 静态成员声明时不能添加缺省值因为静态成员要在类外部定义初始化不属于某个对象而声明时的缺省值是用于初始化列表进行初始化的静态成员不走构造函数的初始化列表路线。
class A
{
public:static int _b;//开放静态成员,可外部访问static void func(){cout _a endl;cout _b endl;//cout _c endl;//3. 4. 静态成员函数没有this指针无法调用非静态成员报错}void Print(){cout _a endl;cout _b endl;cout _c endl;}void Set(int a){_a a;}
private://1. 8. 声明时的缺省值用于初始化列表而静态成员不在构造函数中定义所以不能有缺省值//static int _i 1;//错误static int _a;//私有静态成员int _c 0;
};int A::_a 1;
int A::_b 1;int main()
{A aa1; //_a _b _caa1.Print();// 1 1 0A aa2;//2. 对象aa2修改静态成员_a后aa1打印出来_a也随之改变aa2.Set(2); //_a _b _caa1.Print();// 2 1 0A::func();// 2 1aa2.func();return 0;
}
友元
友元分为友元函数和友元类其提供了一种突破类访问限定符封装的方式将函数声明或者类声明的前面加上friend关键字并且将其放到一个类里面就构成了友元声明。 外部友元函数可以访问类的private和protected的成员友元函数只是一个声明而不会成为该类的成员函数友元声明可以在类定义的任何地方声明不受访问限定符的限制一个函数可以是多个类的友元函数友元类中的成员函数都可以是另一个类的友元函数都可以访问另一个类中的private和protected成员友元类的关系是单向的不具有交换性若A类是B类的友元类则B类可以访问A类的成员但B类不是A类的友元类就不能访问除非也在B类中加上A类的友元声明友元关系不具有传递性如果A类是B类的友元B类是C类的友元不代表A类就是C类的友元而需要单独声明友元有时提供了一定的便利性但友元会增加耦合度破坏封装性所以友元不宜多用。 class B;class A
{
public://PPrint是A类的友元函数可以访问其方法和成员friend void PPrint(const A aa, const B bb);friend class B;A(char a a, char b a):_a(a),_b(b){}void PrintA() const{cout _a endl;cout _b endl;}
private:char _a;char _b;
};
class B
{friend void PPrint(const A aa, const B bb);
public:B(char a b, char b b):_a(a),_b(b){};void PrintB() const{cout _a endl;cout _b endl;}
private:char _a;char _b;
};
void PPrint(const A aa, const B bb)
{//友元可以访问private和protected成员cout aa._a endl;cout bb._b endl;
}
int main()
{A aa;B bb;PPrint(aa, bb);return 0;
}
内部类
如果一个类定义在另一个类的内部则这个类成为该类的内部类。
内部类是一个独立的类与定义在全局的类相比只是受到了类域的限制和访问操作符的限制所以一个类定义的对象中不会包含其内部类。内部类默认是其外部类的友元类反之不成立。内部类也是一种封装当A类和B类紧密关联A类主要的作用就是为B类服务时就可以设计为内部类若放到private和protected中那么A类就为B类的专属内部类其它地方将无法使用。
class A
{
public://构造函数A(int a 1):_a(a){cout A(int a 1) endl;}//拷贝构造函数A(const A aa){cout A(const A aa) endl;_a aa._a;}//析构函数~A(){cout ~A() endl;_a 0;}void PrintA(){cout void PrintA() endl;//B()._b;//不能直接调用B类的成员变量需要友元声明B().PrintB(A());}
private:int _a 1;//A类的私有内部类class B{public://friend class A;void PrintB(const A aa){cout void PrintB(const A aa) endl;//可以直接调用A类的成员变量因为内部类默认为外部类的友元类cout aa._a endl;}private:int _b;};
};
int main()
{A a1(2);a1.PrintA();return 0;
}运行结果 图示结果分析可知对象a1先构造然后调用PrintA函数PrintA函数中创建了一个匿名对象来调用B类中的函数PrintB所以打印出来的结果为1
也说明B作为内部类可以直接调用A类的成员变量是A的友元类但反之A默认不是B的友元需要单独声明。
匿名对象
特点
用 类型(实参) 的方式定义出来的对象叫做匿名对象而之前定义对象的方式 类型 对象名(实参) 定义出的对象叫有名对象
匿名对象的生命周期只在其所在的一行当需要定义一个对象临时使用时就可以定义为匿名对象。
使用方法
类名().成员函数();
#include iostream
using namespace std;class A
{
public:A(int a 1):_a(a){cout A(int a 1) endl;}A(const A aa){cout A(const A aa) endl;_a aa._a;}~A(){cout ~A() endl;_a 0;}void Print(){cout void Print() endl;}
private:int _a 1;
}int main()
{A().Print();//当前行结束后匿名对象就会销毁return 0;
}
匿名对象使用实例补充
万能头文件bits/stdc 会将常用的头文件一并包含。
不建议日常使用只在竞赛时节省时间时有用。
对象拷贝时的编译器优化
在不影响正确性的前提下对连续的构造和拷贝构造进行优化合并从而减少拷贝消耗提高代码速度 图中aa原本为隐式类型转换先构造再拷贝构造但编译器优化为直接构造从而提升效率。
后记
感谢各位读者的阅读欸有不足的地方还是请大家继续指正哈~
本期专栏C_海盗猫鸥的博客-CSDN博客
个人主页海盗猫鸥-CSDN博客
感谢各位的关注~