1.初始化列表
在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值,构造函数体中的语句只能将其称作为赋初值,而不能称作初始化,因为初始化只能初始化一次(初始化的本质就是只能初始化一次),而构造函数体内可以多次赋值
①.以一个冒号开始:接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或者表达式
②.初始化列表是每个成员定义的地方,不管你写不写,每个成员都要走初始化列表,不写的话,内置类型为随机值,自定义类型会调用默认构造
③.在声明给值是缺省值而非定义,这个缺省值是给初始化列表用的,如果初始化列表没有显式给值,就用这个缺省值,如果显式给值,就不用这个缺省值
④.每个成员在初始化列表中只能出现一次(初始化只能初始化一次)
⑤.类中包含以下成员,必须在初始化列表位置进行初始化
引用成员变量 - 引用必须在定义的时候初始化,而初始化列表是每个成员定义的地方
const成员变量 -const常量必须在定义的时候初始化
自定义类型成员(该类没有默认构造函数)
⑥.成员变量在类中的声明顺序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
2.explicit关键字
构造函数不仅可以构造与初始化对象,对于单个参数的构造函数,还具有类型转换的作用
A aa2=2;
//用2构造一个临时对象,再用这个临时对象拷贝构造aa2
//但编译器会优化,直接用2构造对象,只需要调用一次构造函数,而不用先调用构造函数再拷贝构造
const A&ref=2;
//必须用const修饰,因为2会生成一个临时变量,临时变量具有常性
类似
int i=0;
double d=1.1;
i=d;
//中间会生成一个临时变量
c++11支持多参数的转换
B bb2={2,2};
const B&ref={3,3};
如果用explicit修饰构造函数,将会禁止单参构造函数的隐式转换
3.static成员
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称为静态成员变量,用static修饰的成员函数,称为静态成员函数,静态的成员变量一定要在类外进行初始化
①.静态成员为所有类所共享,不属于某个具体的实例(静态成员变量属于整个类)
②.静态成员变量必须在类外定义,定义时不添加static关键字
在类内 static int n;
类外 int A::n=0;
③.类静态成员既可用类名::静态成员 也可以用对象.静态成员来访问
④.静态成员函数没有隐藏的this指针,不能访问任何非静态成员
⑤.静态成员与类的普通成员一样,也有public,private,protected3种访问级别,也可以具有返回值
A*ptr=nullptr;
cout<n<m<<endl;
这里ptr->n,虽然ptr是空指针,但是n是静态成员变量,与用空指针调用成员函数一样,都是可以的
有没有解引用,不能看形态,要看存放的位置
static int&getm(){
return m;}
用引用返回,可以修改m
++A::getm();
私有与保护限制的是不能在类外访问,但是这个函数返回m不受影响
实现一个类,计算程序中创建出了多少个类对象
class A{public:A(){++n;++m;}A(const A&t){++n;++m;}~A(){--n;}private:int m;int n;
};
m代表一共创建了多少对象
n代表目前还有多少对象
求1+2+3+…+n,要求不能使用乘除法,for,while,if else,Switch case,位运算
class solution{class sum{public:sum(){_ret+=i;_i+=1;} };public:int getsum(int n){sum a[n];return _ret; }private:static int _ret;static int _i;
};
int solution::_ret=1;
int solution::_i=0;
4.友元
友元分为:友元函数和友元类
友元函数提供了一种突破封装的方式,有时提供了便利,但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元函数
比如之前想要重载<<符号,cout的输出流对象和隐藏的this指针都在抢第一个参数的位置,this指针默认是第一个参数,但如果构造正常函数,将this指针放在第二个参数,会导致类外无法访问私有成员,故采用友元
友元函数可以直接访问类的私有成员和保护成员,它是定义在类外的普通函数,不属于任何类,不是类的成员函数,但需要在类的内部声明,声明时需要加friend关键字
①.友元函数不能用const修饰,静态成员函数也不能用const修饰,因为const修饰的实质上是形参this指针,而友元函数和静态成员函数都没有this指针
②.友元函数可以在类定义的任何地方声明,不受类访问限定符的限制
③.一个函数可以是多个函数的友元函数
④.友元函数的调用与普通函数的调用和原理相同
友元类
①.友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类的非公有成员
②.友元类是单向的,不具有交换性
③.在time类中声明date类为其友元类,那么可以在date类中直接访问time类的私有成员变量,但不能在time类中访问date类的私有成员变量
④.友元关系不能传递,如果B是A的友元,C是B的友元,不能说C是A的友元
class Date;//前置声明
class Time;
{friend class Date;//声明Date类是Time类的友元类,可以在Date类中直接访问Time类的私有成员变量public:Time(int hour,int minute,int second):_hour(hour),_minute(minute);,_second(second);{}private:int _hour;int _minute;int _second;
};
class Date{public:Date(int year=1900,int month=1,int day=1):_year(year);,_month(month);,_day(day);{}void settimeofdate(int hour,int minute,int second){_t.hour=hour;_t.minute=minute;_t.second=second;//因为已经声明了Date类为Time类的友元类,故Date类可以访问Time类的私有成员变量}private:int _year;int _month;int _day;Time _t;
};
5.内部类
如果一个类定义在另一个类的内部,这个内部类就叫做内部类,此时内部类是一个独立的类,不属于外部类,不能通过外部类的对象去调用内部类,外部类对内部类没有任何优越的访问权限
内部类是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员,但是外部类不是内部类的友元(友元关系不具有交换性)
①.内部类可以定义在外部类的Public,protected,private都是可以的
②.内部类可以直接访问外部类的static,枚举成员,不需要外部类的对象/类名
③.sizeof(外部类)=外部类,和内部类没有任何关系
#include <iostream>
using namespace std;
class A{private:static int k;int h;public:class B{public:void fun(){k=1;//内部类可以直接访问外部类的static,不需要对象名/类名A aa1;aa._h=1;//内部类是外部类的友元类,可以访问外部类的私有成员变量}};
};
int A::k=0;