[C++]类和对象的explicit关键字和static成员 explicit关键字构造函数不仅可以构造与初始化对象 对于单个参数或者除第一个参数无默认值其余均有默认值和全缺省值的构造函数还具有类型转换的作用。explicit关键字就是用来禁止其类相关的隐式类型转换。来看下面代码classA{public:A(intn)//默认构造函数只有一个参数{coutn nendl;}A(constAa)//显式定义拷贝构造函数{coutA(const A a)endl;}};intmain(){Aa1(1);Aa2(a1);//用a1初始化a2需要调用拷贝构造函数A a32;//编译可以通过return0;}运行结果n1A(constAa)n2上面代码中我们发现用整型2对自定义类型A的对象a3进行初始化的语句可以通过编译并且运行时发现A类的构造函数被调用了而传入的参数正就是我们的整型2。编译可以通过是因为发生了隐式的类型转换 这里整型2和自定义类型对象a3的类型不同但是自定义类型A有一个单个参数的构造函数这个时候编译器就会调用A类的构造函数传入参数整型2进行初始化并将其转换的结果存储到一个该自定义类型的临时变量里用这个临时变量对a3对象进行初始化。但是我们发现在这个过程中并没有调用拷贝构造函数来使用这个临时变量对a3进行初始化这是因为编译器在对某对象初始化时遇到了连续的调用构造函数和拷贝构造函数时则会优化为调用一次该对象的构造函数对对象进行初始化。上面的代码是单个参数的构造函数时存在的隐式类型转换多个带缺省值参数的构造也可以进行类型转换。来看下面代码classB{public:B(inta0,intb0,intc0):_a(a),_b(b),_c(c){;}voidDisplay()//输出该类的成员变量的值{couta _a b _b c _cendl;}private:int_a;int_b;int_c;};intmain(){B b11;b1.Display();B b2{1,2};b2.Display();B b3{1,2,3};b3.Display();return0;}运行结果a 1 b 0 c 0 a 1 b 2 c 0 a 1 b 2 c 3上面在对三个自定义类型的对象进行初始化过程中使用了花括号包含参数列表的方式来表示进行类型转换时调用其自定义类型的构造函数所用的参数。但其实这种方式的类型转换会让代码的可读性变差如果我们不希望我们写的类发生上面这种隐式的类型转换 我们就可以在类的构造函数的定义前加上explicit关键字来禁止该自定义类型的类型转换。classB{public://explicit关键字禁止该自定义类型发生隐式的类型转换explicitB(inta0,intb0,intc0):_a(a),_b(b),_c(c){;}voidDisplay()//输出该类的成员变量的值{couta _a b _b c _cendl;}private:int_a;int_b;int_c;};这个时候我们再像上面那样用花括号的形式来进行类型转换就会发生编译错误。B 的复制列表初始化不能使用显式构造函数 B 的复制列表初始化不能使用显式构造函数 “初始化”: 无法从“int”转换为“B” 不存在从 int 转换到 B 的适当构造函数 复制列表初始化不能使用标记为“显式”的构造函数 复制列表初始化不能使用标记为“显式”的构造函数static静态成员对象在C语言中用static修饰函数会改变其链接属性使其无法被外部调用而用static修饰变量时则会改变变量的生命周期使其变成静态变量。而我们的static也可以修饰类里的成员声明为static的类成员称为类的静态成员。静态成员变量用static修饰的成员变量称为静态成员变量。静态成员变量一定要在类外进行初始化。#includeiostreamusingnamespacestd;//static成员变量classTest1{public:inta0;staticintcount;//声明静态成员变量Test1(){count;}//每创建一个Test1的对象就count};//初始化Test1的静态成员变量intTest1::count0;intmain(){Test1 t1[10];//调用10次该类的构造函数coutt1[0].countendl;//通过对象来访问静态成员变量coutTest1::countendl;//通过类名来访问静态成员变量coutsizeof(Test1)endl;//计算类Test1的大小return0;}运行结果10 10 4声明为static的成员变量具有静态属性其不属于具体的某个对象而是属于类。该类的每个对象都共同享有该静态变量 所以我们不仅可以通过对象访问到静态成员变量count也可以通过类名来进行访问。在我们通过sizeof来计算自定义类型Test1的大小时但只有4个字节一个成员a的大小 而不是8个字节成员 a 静态成员变量count。这是因为类的静态成员存储在内存的静态区。当没有类的对象创建时这个静态成员变量也存在于内存空间中所以该静态成员变量不计入类的内存大小这和类的成员函数类似在内存中只有一份被所有对象所共有。静态成员函数用static修饰的成员函数称之为静态成员函数。#includeiostreamusingnamespacestd;//static成员函数classTest1{public:inta0;staticintcount;//声明静态成员变量Test1(){count;}//每创建一个Test1的对象就count//声明静态成员函数staticvoidDisplay(){//cout a ; 错误静态成员函数不能访问该类中的非静态成员coutcount countendl;}};//初始化Test1的静态成员变量intTest1::count0;intmain(){Test1 t1[10];//调用10次该类的构造函数Test1::Display();//通过类名来调用该类的静态成员函数t1[0].Display();//通过对象来调用该类的静态成员函数return0;}运行结果count10count10静态成员函数和静态成员变量类似静态成员函数不属于某个具体的对象而是属于类的 因此静态成员函数不属于某个具体的对象。静态成员函数不存在成员函数隐藏的this指针通过对象调用该类的静态成员函数时不会传入指向该对象的this指针。因此静态成员函数不能够访问本类中的非静态成员变量只能访问静态成员变量。例如上面的代码中静态成员函数Display()不能访问Test1类中的int a成员变量。