在类与对象的上和中已经把类与对象的大部分内容讲了,这里对最后的一些内容进行补充说明。
目录
一、初始化列表
二、类型转换
三、static成员
四、友元
五、内部类
六、匿名对象
一、初始化列表
之前我们在实现构造函数的时候,初始化成员变量主要是使用函数体内赋值,构造函数初始化还有⼀种⽅式,就是初始化列表,初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式。每个成员变量在初始化列表中只能出现一次,从语法上来看,初始化列表是成员变量定义初始化的地方。
引用成员变量、const成员变量、没有默认构造的类类型变量必须放在初始化列表的中进行初始化。C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显⽰在初始化列表初始化的成员使⽤的。
初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆关。建议声明顺序和初始化列表顺序保持⼀致。对于没有显⽰在初始化列表初始化的⾃定义类型成员会调⽤这个成员类型的默认构造函数,如果没有默认构造会编译错误。
#include<iostream>
using namespace std;class Date
{
public:Date(int year=1949, int month=10, int day=1)//成员变量的定义初始化:_year(year)/*,_month(month),_day(day)*/{}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private://成员变量的声明//当初始化列表中没有对参数进行初始化时 就会用这里的默认值对形参进行初始化int _year;int _month=2;int _day=2;
};int main()
{//这里只给第一个参数进行了传参 后面两个参数会采用设置的默认值//但是我们在初始化列表的位置并没有对_month和_day进行初始化//所以用的是变量声明位置的缺省值对变量进行初始化 打印的结果为1949/2/2Date d1(1949);d1.Print();return 0;
}
二、类型转换
C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数,在构造函数前⾯加explicit就不再⽀持隐式类型转换。
#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1, int month = 1, int day = 1):_year(year),_month(month),_day(day){}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{//这里隐藏了一个类型转化 编译器先用1949构造了一个临时对象 再用这个临时对象拷贝构造了d1//(Date)1Date d1=1949;d1.Print();//当有多个参数的时候要用{}Date d2 = { 2001,10,1 };d2.Print();return 0;
}
三、static成员
用static修饰的成员变量被称为静态成员变量,静态成员变量要在类外进行初始化。静态成员变量不属于某个对象,它是这个类实例化出的所有对象共享的,所以它不存在对象中,存放在静态区中。
用static修饰成成员函数被称为静态成员函数,静态成员函数没有this指针。静态成员函数中可以访问其他的静态成员,因为没有this指针,所以不能访问非静态成员变量。非静态成员函数可以访问任意的静态成员变量和静态成员函数。
可以通过类名::静态成员 或者 对象.静态成员 来访问静态成员变量和静态成员函数。
静态成员也是类的成员,受public、protected、private 访问限定符的限制。静态成员变量不能再声明位置给定缺省值,因为声明部分的缺省值是用于构造函数初始化列表的,静态成员变量不属于对象,不能用构造函数初始化列表来初始化。
#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){//非静态成员函数可以调用任意的静态成员变量和静态成员函数++_count;}//静态成员函数可以调用静态成员变量static int GetCount(){return _count;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;static int _count;
};//初始化时要加上作用域运算符 这里可以用来统计实例化出了多少个对象
int Date::_count = 0;int main()
{Date d1 = 1949;d1.Print();Date d2 = { 2001,10,1 };d2.Print();//两个值输出时都是2 static定义的静态成员变量是所有类对象共享的cout << "d1 count=" << d1.GetCount() << endl;cout << "d2 count=" << d2.GetCount() << endl;return 0;
}
四、友元
在一些特殊的情况,我们会在类外需要访问类内private或者protected修饰的成员变量或成员函数,这个时候我们就可以用到友元。友元分为:友元函数和友元类,在函数声明或者类声明的前面加上friend,并且把友元声明放到一个类里面。友元函数只是一种声明方式,并不是一个类的成员函数。友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制。一个函数可以是多个类的友元函数。友元类中的成员函数都可以看作是另外一个类的友元函数,都可以访问另外一个类中的私有和保护成员。
友元类的关系是单向的,它不具有交换性和传递性。比如说A类是B类的友元,但是B并不是A的友元;如果A类是B类的友元,B类是C类的友元,但是A类并不是C类的友元。
#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){ }void Print(){cout << _year << "/" << _month << "/" << _day << endl;}//友元函数在声明的时候形参部分可以只写参数类型friend void Modify(Date&);
private:int _year;int _month;int _day;
};
//函数在外部定义 要去掉friend 这个时候就可以直接访问类内的私有和保护成员了
void Modify(Date& d)
{d._year = 1;d._month = 1;d._day = 1;
}int main()
{Date d1(2000,10,10);d1.Print();Modify(d1);//这里就成功的修改了类内的私有成员d1.Print();return 0;
}
五、内部类
如果一个类定义在另外一个类的内部,这个内部定义的类就叫做内部类。内部类是一个独立的类,跟定义在全局相⽐,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。也就是说如果一个类中定义了一个内部类,那么在计算机这个类的大小时,并不会因为有这个内部类而发生改变,内部的这个类除了类域和访问权限受到限制,其他和定义在全部的类是一样的。同时内部类默认时外部类的友元类。
六、匿名对象
⽤ 类型(实参) 定义出来的对象叫做匿名对象,相⽐之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象。匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可,就可以定义匿名对象