1.初始化列表
形式:
Date(int year,int month,int day) :_year(year) ,_month(month) ,_day(day) {}
以冒号开始,以逗号分隔
介绍:
为了解决没有默认构造的自定义类型的初始化和某些必须在定义时初始化的对象
- 自定义类型初始化:没有默认构造+想要显示调用
- 在定义时初始化的对象:引用&,const只能初始化一次
函数体可以多次赋值,但是初始化列表只能初始化一次
那些需要初始化列表的对象:
- 引用&:int& _s;只能初始化一次
- const:const int _s;只能初始化一次
- 自定义类型:A _s;①默认构造函数②显示初始化
初始化顺序:
按声明顺序初始化,与初始化列表内顺序无关
private: int _d2; int _d1; Date(int d1,int d2) :_d1(5) ,_d2(d1) {}
可以看出 ,声明中先d2再d1 , 列表中先定义d1再定义d2 ,
但是 ,因为先定义d2 , d2(d1)
这个时候d1还没有初始化,所以d2初始化为随机值
初始化几种方式:
- 类中声明(缺省值)
private: int _year=2004; int _month=8; int _day=19;
- 函数体中定义
Date(int year,int month,int day) { _year=year; _month=month; _day=day; }
- 初始化列表定义对象
Date(int year,int month,int day) :_year(year) ,_month(month) ,_day(day) {}
目前初始化的方法:
内置类型:
- 声明中的缺省值
- 初始化列表
- 函数体
- 不初始化,随机值
自定义类型:
- 初始化列表
- 调用默认构造函数
!不是初始化能做到一切,比如在开空间时的检查(if a==_nullptr)
其他explicit关键字
- 作用:关键词修饰构造函数,禁止类型转换
class A { private: int _a; public: explicit A(int a) :_a(a) {} };
- 类型转换
A aa=3;//内置类型隐式转换成自定义类型
这个时候整型int3就会转换int成自定义类型
1.单参数才能转换
2.不是所有转换都能发生,比如指针和整型差太多了
const A&a=3;
多参数的类型转换
class date { private: int _year; int _month; int _day; public: date(int year=2004, int month=8, int day=10)//注意看,这里有两个缺省值。如果没有,会报错。这是多参数隐式转换的方法 :_year(year) ,_month(month) ,_day(day) {} }; int main() { date d1=(2004,8,19);//默认是一个逗号表达式,取最后的19 date d2=19; }
可以看到,d1和d2都赋值给了year
加上关键字后,无法发生隐式转换,但是依旧可以强制转换
A aa=(A)3;
2.Static对象和函数
静态成员变量
static int _count;
- 不支持给缺省值
因为缺省值是给初始化列表的,但是静态成员不在列表初始化- 声明在类内,定义在类外
如何在主函数内得到静态成员变量_count的值?
1.private——>public
- A::_count
- A d1;
d1._count;
必须要实例化对象才能得到_count,需要-1
但是将变量改成public很不安全
2.还有一种方法,就是将函数改成静态成员函数
静态成员函数
static void get() { return _count; }
- A()匿名对象
也需要-1
cout<<A().get()<<endl;void get() { return _count; }
A d1;
d1._count;
必须要实例化对象才能得到_count,需要-1将函数改成静态成员函数
没有this指针,函数内不能得非静态成员变量了
3.友元
提供了一种冲破封装的方法
友元函数
class A { friend int add(int _a,int _b); private: int _a; int _b; }; int add(int _a,int _b) { return _a+_b; }
可以在类里面定声明一个友元函数,在类外定义,这样就可以访问类中的私有成员变量。
友元类
class A { friend class B; }; class B { };
B可以用A中的成员变量
友元关系是单向的,B是A的友元,但是B不是A的友元
没有交换性
没有传递性(A是B的友元,C是A的友元,但是C不是B的友元)
友元不能继承
4.内部类
class A
{
public:
class B
{
};
};
- 内部类是外部类的友元函数
- sizeof(外部类)=外部类
- 如果想要内部类是外部类一个人的小甜心,别人都不能调用,可以设置成private
class A { private: class B { }; };
5.匿名对象
主函数内,不用实例化,不用起名字,可以直接拿来用
class A
{};
int main
{
A();
}
class date
{
private:
int _count;
public:
is()
{
return _count;
}
};
int main
{
date().is();
}
- 不用取名字
- 生命周期只有这一行,之后会自动调用析构函数
6.拷贝对象时的一些编译器优化
前提:在一行内才可以优化,在下面会举实例
构造+拷贝构造——>构造
class A { private: int _a; public: A(int a) :_a(a) { printf("构造函数\n"); } A(const A& d) { _a = d._a; printf("拷贝构造函数\n"); } ~A() { printf("析构函数\n"); } }; void funk(A b) { } int main() { A a(3); funk(a);//不优化 printf("————————\n"); funk(A(3));//优化 printf("————————\n"); funk(3);//优化 printf("————————\n"); }
可以看出后两次被优化了
拷贝构造+拷贝构造——>拷贝构造
class A { private: int _a; public: A(int a) :_a(a) { printf("构造函数\n"); } A(const A& d) :_a(d._a) { printf("拷贝构造函数\n"); } A& operator=(const A& aa) { cout << "A& operator=(const A& aa)" << endl; if (this != &aa) _a = aa._a; return *this; } ~A() { printf("析构函数\n"); } }; A funk2()//传值返回 { A aa(3); return aa; } int main() { //传值传参和传值返回,都是一次拷贝构造 A a1 = funk2();//优化 printf("————————\n"); A a2(2);//不优化 a2 = funk2(); printf("————————\n"); }