这一讲是直接照搬的郑莉老师的《C++程序设计》第5章和第六章。我上的课程中,老师没有提到static这个内容;但是static经常见到,但是我不明白道理具体是啥。这里刚好复习一下。
主要内容:
- 类的静态成员
- 静态数据成员
- 静态函数成员
- 通过函数指针,调用普通成员函数+静态成员函数。
- 全局函数
- 内联函数
- 全局函数调用
- 执行机制
- 嵌套机制
- 递归调用
- static_cast
一、类的静态成员 static in class
- 全局变量是实现数据共享的方法,但是和类的私有变量相矛盾。
- 实现类的对象和对象之间的数据共享,可以使用静态成员。
- 静态成员属于类,由某个类的对象共同拥有。
- 静态成员分为“静态数据成员”&“静态函数成员”
(1)静态数据成员
- 类的一种数据成员(member variables),被类的所有对象分享(因此所有对象在这个数据上都一样)。只要储存一次,就能够提供给所有对象使用,从而节省空间。
- 静态数据成员能够被类的对象or类更改,一个对象改了它,对所有对象都有效。
- 使用:首先在类的private定义静态数据成员,static type name;然后在main函数之前,声明一下静态数据成员的初值,type class_name::name = 初值。
- 模板
class
- 例子
#include
结果:
This circle is radium = 1.
This circle is radium = 2.
r1 circum = 6.28318, and area = 3.14159
r2 circum = 12.5664, and area = 12.5664
Destroy radium = 2.
Destroy radium = 1.
(2)静态函数成员[1]
- 声明和定义与静态数据成员差不多,在返回值前面加上static关键字。
- 成员函数一般都是public,因此通过类名限定or对象名限定来调用,非静态成员只能够通过对象名调用。
- 也就是说,如果ClassName这个类中,定义了普通成员函数f1和静态成员函数f2,那么调用f1的只有ClassName生成的对象才行,而f2不仅能通过对象调用,还能够直接被ClassName调用(ClassName::f2()是ok的)。
- 例子
#include
运行结果
This is static.
This is ordinary.
This is static.
by ordinaryFunc: 1
by staticFunc: 1
by Somthing::staticFunc: 1
(3)通过函数指针调用成员函数
- 回忆函数指针的用法:
//type1是函数的返回值的类型,没有返回值就是void;type2和type3是传参var1和var3的类型。
实际上,下面的类的各种成员函数的用法在此模板上基本一致。
- 指向类的成员函数指针,指定类名即可(&类名::成员函数名)
- 通过指针调用普通成员函数(non-static)
- 一定要有对象实例p1,才能够调用。
- 没有传参的话,那么把type2 var2, type3 var3空着就好。
- 用的时候,是“对象名.*函数指针名”。
- 通过指针调用普通成员函数(non-static)
type1
-
- 调用静态成员函数,不需要实例化
- 不用对象实例p1,直接能够调用。
- 同时,鉴于静态函数的特殊性,指针定义的地方不用指明类名——因为静态函数是在全局可用。
- 用的时候,直接用函数指针名,*也不用。
- 调用静态成员函数,不需要实例化
type1
- 例子
#include
运行结果
This is ordinary.
1.1
1
This is static.
2.1
1
可以看到,以上是①类②不同成员函数的函数指针③静态成员函数的函数指针的用法。如何定义函数指针+如何传参+是否有返回值+是否要用对象调用。
二、全局函数
1、定义
- 主函数main能够调用全局子函数和类的成员函数,全局子函数之间、类函数之间、全局子函数和类的成员函数之间能够相互调用;主函数不能够被其他函数调用。
- 先声明某个全局子函数而不用定义,然后写主函数(主函数中调用子函数),最后定义子函数。
#include
2、内联函数[2]
- 函数调用也会降低程序效率(好吧。。)
- 逻辑:调用函数的时候,CPU需要保存现场和返回地址(一会儿得返回的地方),然后再转移到子函数的代码起始地址执行。子函数执行完毕,取出先前保存的返回地址和现场状态,在继续执行,因此,如果频繁调用,需要很多空间和时间开销(好吧,我知道我的Python代码又可以提高效率了。。)
- 对于复杂的函数,调用函数的任务量反而比不上函数本身的运行时间;但是如果是小型函数,调用时间比运行时间还长。
- 解决:内联函数,不是在调用时发生转移控制,而是在编译时,将函数整体嵌入在每一个调用处。当编译器编译代码的时候,所有的inline函数就直接放过来,而不是调用。缺点是:inline函数将会让编译代码变大。
- 使用的时候,要写上inline关键字。格式:
- inline 返回类型 成员函数名(形式参数表){函数体}
- 注意点:
- 内联函数不能够作为函数重载的区分标志(?谁会没事写两个重名函数。。)
- 内联函数体内一般不能够有循环和switch语句。
- 内联函数的定义,必须出现在第一次被调用之前,和普通函数不同。
- 不能够进行异常接口的声明(??)。
- 在类中定义的函数,即使不加inline,也默认为内联函数(??所以类中的函数都是超级有效的??)
- 例子
#include
因为使用了两次,因此内联函数能够减少调用时间。以后我写python,也得加上inline。。
三、全局函数的调用
- 函数调用的执行机制、嵌套机制、递归调用。
1、执行机制
例子,冒泡排序
#include
结果:
Enter the array length : 5
Enter 5 numbers in your array :
12
34
1
56
-1
This is after sort :
-1 1 12 34 56
2、嵌套调用
- 函数1调用了函数2,然后依次返回结果。
例子:
#include
这个函数反复进行了调用:CalArea调用了CalDistance,CalDistance调用了Square,Square调用了类里面的getX和getY。
3、递归调用
- 调用一个函数的时候,直接或者间接调用函数自己(※※※)。这个思想在分治法divide and conquer算法中很重要,而分治法又是非常重要的算法,用李佳琦的话——OMG!!所有MM们、GG们看过来,赶紧学它学它学它!!!我在这一块真的学得稀烂。。递归法就好像斗转星移一样,能够以彼之道还治彼身~
- 直接调用自己
void
-
- 间接调用自己
void
- 递归算法:将原问题拆解为新的规模较小的问题,解决新问题有用到了原问题的解法。应该包括两个重要的内容
- 递归结束条件:当满足条件的时候,不需要再递归调用。
- 递归调用语句。
例子:
#include
输出:
Enter the number : 5
The factorial of 5 is 120
四、static_casting[3]——explicit type conversion
1、type casting
C++中存在5种不同类型的casts:C-style casts,static casts,const casts,dynamic casts,reinterpret casts。后四种称为named casts。
2、C-style casts
int
3、static_cast——将A类型转为B类型
typeA
参考书籍:
C++程序设计/郑莉,李超编著.——北京:机械工业出版社,2012.1.
参考
- ^https://blog.csdn.net/Windgs_YF/article/details/99762327
- ^https://www.learncpp.com/cpp-tutorial/75-inline-functions/
- ^https://www.learncpp.com/cpp-tutorial/explicit-type-conversion-casting-and-static-cast/