初始化列表:
之前所说的构造函数初始化严格意义上来说不能叫变量初始化,只能是称为赋初值,C++给出了初始化列表的概念
标准写法:
class Date
{
public:Date (int year ,int month, int day):_year(year),_month(month),_day(day){}
private:int _year;int _month;int _day;
};
以冒号开始,逗号分隔
之所以要提出初始化列表的操作,是因为有一些变量不得不在声明的时候给予初值,如引用,const变量、没有默认构造函数的自定义变量,这三者如果不在声明的时候马上给予初值,编译器将会报错。
易错点:
观察下列代码:
class A
{
public:A(int a):_a1(a),_a2(_a1){}
private:int _a2;int _a1;
};
假设实例化一个A对象,传值a=1,猜测一下输出_a1,_a2是什么,你可能会认为是1 1,其实不然,对于初始化列表而言,它不是从上到下一次初始化的,而是根据变量声明的顺序初始化的,显然_a2比_a1更早声明,列表会优先初始化_a2,此时_a1还处于随机值的状态,故最终的结果是输出 1 随机值.
正确的使用方式:
①:
A a(1);//单参
A a(1,2); //多参
②:
A a=1; //单参
A a={1,2}; //多参
我们讨论一下第二种方式为什么正确,编译器在此做了一个隐式类型转换,将int类型的1转换成了A类型的变量存储在一个临时变量中,接着临时变量将值传给a
说白了就是一次构造函数+一次拷贝构造函数,一些新版本的编译会在此将其优化成一次构造。
在构造函数前附加explicit关键字可以使第二种方式失效
匿名对象:
正如C中结构体有匿名结构体一样,C++中对象也有匿名对象
//匿名对象
class A{……};
A();
匿名对象的生命周期非常短,只有当前所在的一行,可以说是一次性用品。
之前所提到的隐式类型转化其实就是生成了一个匿名对象作为媒介完成的。
static成员:
static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的
成员函数,称之为静态成员函数
在一些特定场景下,我们在类中需要有静态成员变量和静态成员函数,我们知道静态变量的声明周期是全局的,仅可声明一次,故可以推出类中的静态成员变量和函数不属于类中,他们在类声明的时候就已经生成了实际空间。
因此在类中初始化static成员变量是会报错的,static成员变量需要在类外定义
class B
{
private:static int _b;
};
int B::_b=0;
易错点:
class C
{
public:static void Print(){cout<<_c<<endl;}
private:int _c=1;
};
上面的代码是错误,原因是因为静态成员函数没有默认的this指针,无法访问类中的元素,但是既然没有this指针,我们就可以不需要通过实际对象去调用类中的函数,如
class C
{
public:static void Print(){cout<<"C++"<<endl;}
};
int main(){C::Print();return 0;
}//这样是没有问题的
友元函数:
有些时候为了方便起见我们会想让外部函数可以访问类中的私有属性,故C++引入了友元函数使得这一目的得以实现
class Date
{
friend void Print(const Date& para);
private:int _year=2024;int _month=1;int _day=1;
};
int main(){Date d1;Print(d1);return 0;
}//可以通过
友元函数不具有交换性(A是B的友元不代表B是A的友元)和传递性
————————————————————————————————————