C++中的初始化列表、const修饰的成员、友元类和友元函数、内联函数、static成员、构造函数的优化

我的c++笔记整理

初始化列表

初始化列表以一个冒号开始,每个数据列表以逗号隔开。

一、初始化列表可以提高效率 ,尽量使用初始化列表

初始化列表不论你写还是不写,系统都会自己调用的

从下面的单步调试过程可以看出来,Date类成员变量中有一个自定义类型Time时间类Date日期类的构造函数调完我们自己写的初始化列表后,并不是就执行函数体,而是去调Time的构造函数,从而对自己的成员变量进行初始化。很明显我们并没有对_time写初始化

一般情况下我们不会传Time类对象的成员变量,而是会直接传Time类对象

如下图所示:

我们用带初始化列表和不带初始化列表两种情况来验证初始化列表可以提高效率


二、有的成员变量必须用初始化列表来进行初始化

1.常成员变量必须在初始化列表中初始化(常量创建时必须初始化)

2.引用类型的成员变量必须在初始化列表中初始化(引用创建时必须初始化)

3.没有缺省构造函数的成员变量必须在初始化列表中初始化(必须传参来调用其带参的构造函数)

三、成员变量按照声明顺序来进行初始化,并不是初始化参数列表顺序

我们可以看到,要是按照初始化列表顺序进行初始化则应该得到 29/29/29, 很明显这里的年和月都是随机值,因为先初始化_yeay,而此时的_day还没有进行初始化就是随机值,而用这个随机值来初始化_year,_month



const修饰的成员

1const 对象不可以调用非const成员函数

例如当对象调用show()函数时其实时将对象的地址传递过去

在函数后面加const,将成员函数变为常成员函数

这样的话不管是const对象还是普通对象都可以调用该对象
但是此时该对象不可以更改

一般我们建议说,只要在函数内部不改变对象就可以加const

2 const成员函数不可以调用非const成员函数
例如,下面的show()const成员函数不可以调用func()非const成员函数

得出以下结论:

1.const对象不可以调用非const成员函数

2.const对象可以调const成员函数

3.const对象可以调非const成员函数

4.const对象可以调const成员函数

5.const成员函数不可以调非const成员函数

6.const成员函数可以调const成员函数

7.const成员函数可以调非const成员函数

8.const成员函数可以调用const成员函数

也就是const不可以调用非const, 其他的都可以调用 (权限不可以被放大,但可以能被缩小)

C++中的友元

一、友元类

如我们上面的Date类和Time

在类域外面是不可以直接访问类中的私有成员的若我们想通过Date类来访问Time类中的私有成员

可以通过将Date类定义为Time类的友元类
 
 
class Time{ friend class Date;public:Time(int hour=0,int minute=0,int second=0)\:_hour(hour)\, _minute(minute)\, _second(second){cout << "Time构造函数\n";}
void show() 
	{
		cout<< _year << " /" << _month << " /" << _day << endl;
		cout << _time._hour << " :" << _time._minute << " :" << _time._second << endl;
	}

而且此处应该注意,若是 想在Date类中访问Time类中的私有成员函数,是将Date类声明为Time 类的友元类

二、友元函数

其实我们不推荐使用,因为友元会破坏类的封装性

但是在有的情况下友元又会特别合适,例如,输出输入运算符的重载

当我们想打印日期类的成员变量时,并不可以直接用cout来进行输出,若现在我们不用之前写的show()接口来进行打印,自己来写一个输出运算符的重载。这个时候就可以用友元函数来实现对象的输出


这里的 cout为一个ostream输出流对象(全局对象)

很明显输出输入运算符的重载时适合用友元来实现的。

内联函数

内联函数可以提升程序运行效率,其实是一种以时间换空间的做法

并且只是给编译器的一种建议,编译器会自己优化,如果代码太长或者里面有循环或者递归,即使你加上inline,编译器会自动忽略掉内联,一般情况下定义在类中的函数是内联函数,

 

其实这与编译器的优化程度有很大的关系,以VS013来说,在debug版本中内联函数是没有被展开的,是可以进行调试的


Release版本中将内联函数进行了展开

 

 


static成员



先看一个例子

看上面求出Date类对象的大小,并没有计算count的大小,因为静态数据成员并不是单独属于这个对象,而且这个对象的空间是在栈上开辟的,但是静态数据成员是放在数据段的,
那么这样的话,静态数据成员的初始化就不可以在类的构造函数的初始化列表中完成,必须单独进行初始化。

、静态成员变量

1.当我们把静态成员声明为公有时,可以通过对象和类域来进行访问

2.成员变量声明为私有的,这时后就可以通过 Getcount()这个接口来实现访问静态成员变量, 而且我们把这个函数也定义成static,这样的话就可以它就不属于某个对象,我们也就可以通过类域来调用它。


、静态成员函数没有隐含的this形参

也是因为这一点,在静态成员函数中,不可以访问非静态成员(静态成员都是属于某个对象的,就需要用this 指针来访问),但是非静态成员函数可以访问静态成员(这一点也很好理解,静态成员既可以通过this指针来访问,也可以通过类域来访问)

构造函数的编译器优化

当在同一个式子中编译器会将拷贝构造和构造函数合并为一次(前面的那一个)

一、返回值的优化

1.普通情况下是这样的:


2.编译器进行优化后


上面看到定义一个 Date(), 这是一个匿名对象,它的声明周期是当前行。

二、对参数进行优化
回答下面的问题:
 
  
Test1中调用了_2__次AA的拷贝构造函数,_1__次AA的赋值运算符函数的重载。 Test2中调用了__2_次AA的拷贝构造函数,_0__次AA的赋值运算符函数的重载。 Test3中调用了__3_次AA的拷贝构造函数,_0__次AA的赋值运算符函数的重载。 class AA {}; AA f (AA a) { return a ; } void Test1 () { AA a1 ; a1 = f(a1); } void Test2 () { AA a1 ; AA a2 = f(a1); } void Test3 () { AA a1 ;
 
   
AA a2 = f(f(a1));
}


结束。

猜你喜欢

转载自blog.csdn.net/misszhoudandan/article/details/79765478