C++类与对象(下)

1.再谈构造函数

在中篇里,提到过构造函数,这里提一下构造函数的一个重要的性质:初始化列表

class Date
{
public:
 Date(int year, int month, int day)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 private:
 int _year,_month,_day;
 }

在C++中可以改造为下面的代码

class Date
{
public:
 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)

初始化列表和缺省参数,以及函数内部对成员的赋值是可以共存的,
需要注意的以下几点

  1. 初始化列表里的变量不能重复

  2. 初始化只能初始一次

  3. 某些成员必须在初始化列表里初始化—const成员变量 引用成员变量 自定义成员(没有默认构造函数)

    尽量使用初始化列表初始成员,因为不管你是否使用初始列表初始对 象,函数都会试图先用初始列表初始。

小知识点:成员变量在类的声明次序就是初始化列表的初始次序

class Array
{
public:
 Array(int size)
 :_size(size)
 , _array((int*)malloc(sizeof(int)*_size))
 {}
private:
 int* _array;
 int _size;
};

如果调用这段函数,就会发现系统给_array分配了一个非常大的空间,
这是因为_size并没有初始化是一个随机值,但是编译器根据_size的大小确定给_array的大小,这会导致空间的浪费。
防止的方法是,声明的顺序和定义的顺序要一致
在代码中除了可以这样初始化对象Date d(2018)
还有一种情况是

Date d1(2018);
d1 = 201;

这里需要知道匿名对象,所谓的匿名对象就是没有名字的对象Date(2018)
普通的对象生命周期在函数的作用域内,但匿名对象的生命周期只在定义的那一行存在,即用即销毁,它的作用主要是赋值

Date m=Date(2018);

上面的代码

Date d1(2018);
 
 // 用一个整形变量给日期类型对象赋值
 ///实际编译器背后会用2019构造一个无名对象,最后用无名对象给d1对象进行赋值
 d1 = 2019;

首先2019是int型,Date类的构造函数支持int型的传参和隐式转换有关

1.先用2019构造一个匿名对象。
2.再用匿名对象拷d1。
3.优化为构造函数。

知识点:在C++98前只支持对单参数的类操作,而在C++11里增加到了多参数`d1 = {2018,1,2};
在11年之前的编译器不支持这种写法。
用explicit修饰构造函数,将会禁止单参构造函数的隐式转换。

2.static静态

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰,可以理解为静态成员是属于某个类所有对象。所以不能再初始列表里初始化。
生命周期和全局变量相同,初始化需要再类外初始化具体写法为
静态的成员变量一定要在类外进行初始化。

变量类型 + 类名::变量名 = 赋值;

静态成员变量的用处和C语言里的全局变量类似,但是比全局变量更安全,有利于C++的封装性。

成员函数,称之为静态成员函数。
静态成员函数只能调用静态对象和非成员对象,原因是因为静态成员函数的参数没有this传参,
静态的成员本身也是有private public protected的区别
小知识点C++11支持成员变量在定义时声明直接初始化

class A
{
public:
.......
private:
 // 非静态成员变量,可以在成员声明时,直接初始化。;类似缺省函数
 int a = 10;
...
};

3.友元函数 友元类

所谓的友元可以理解为朋友的关系,一个人和别人是朋友,可以偶尔在别人家里玩,但是还不属于这家人,这个规则在数据世界也成立
ostream<<(ostream& out,Date & d)
{.......
}

重载输出操作符写成这样,但是我们会发现操作失败,这是因为重载完后是类的对象在左边形参在右边,

d1<<cout;

但是这与我们正常的习惯相反,所以我们可以把设置Date为ostream的友元类,让ostream可以访问Date的私有成员
注意的的是,在一个类里可以设置其他的类为自己的友元类,使其他的类能够访问自己的私有成员可以写成

friend &ostream operator<<(ostream out)
{
cout<<_year<<"-"<<_month<<"-"<<_day;
}

友元关系包括友元函数和友元类
友元类可以访问和其有关系的类的private类成员,而自身不属于被访问的类,友元函数也有相同的性质,
提示:为了C++的封装性尽量少使用友元类和友元函数。

4.内部类

内部类就是一个类的内部又定义了一个类,类似下面的例子

class A
{
private:
 static int k;
 int h;
public:
 class B
 {
 public:
 void foo(const A& a)
 {
 cout << k << endl;//OK
 cout << a.h << endl;//OK
 }
 };
};

注意:
如果一个类定义在另一个类的内部,这个内部类就叫做内部类。注意此时这个内部类是一个独立的
类,它不属于外部类,更不能通过外部类的对象去调用内部类。外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元类。注意友元类的定义,内部类可以通过外部类的对象参数来访问外部类中
的所有成员。但是外部类不是内部类的友元。
如果用sizeof判断大小不会将内部类的成员计算进来。
除此之外和普通的类没什么区别。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章