成员函数
前言
1 | class ROLE{ |
谁的成员,无非就是要知道作用域在哪里。
正文
与常规函数不同
1 |
|
这个时候函数add是全局函数,搁哪调用都没问题。
相反的,类中的成员函数,就只能被这个类调用。
1 | class Box{ |
这种时候在主函数中调用test()想都不用想调用的是外面的全局函数
::
之前说过前面没有东西时就代表全局作用域,那么要调用Box的test就要Box::test();
不过由于没有实例化,所以没意义,顶多在外面修改函数
1 | class Box{ |
注意box类中的函数,定义要通过Box::写在外面的话,那么类中的函数只能是声明,否则会报错已有主体
这里就是想在外面写,所以去掉了类中的函数主体。
成员函数的大小
可能这种写法刚从c风格过渡而来时会不习惯,但是一般类中的成员初始化或者函数定义都是写在外面的。
结构体的内存占用存在对齐情况,2 4 8的倍数,这是板上钉钉的事实。
但是类的内存占用呢,变量没办法,声明了就有,但是成员函数,不是每个对象都需要,它的内存占用该怎么办
1 | class Box{ |
发现他在统计类的内存大小的时候,忽略掉了函数?
如果是以为没定义的话其实也陷进去了。
1 | class Box{ |
发现还是忽略的。
但是要注意:虽然统计类的大小时不计函数,但是函数本质上还是有占用的
对象的大小按照数据成员所占空间之和算,和结构体类似。但是类中的函数,是类通用的,所以不算做对象的占用,因此成员函数也不存在对象的内存空间。换言之就可能在调用时才跳转到代码区什么的找到函数的地址。
空类的大小
然后就是另一个有意思的地方。当类是空的时候它的占用会是0吗
ps: C++的空类是指这个类不带任何数据,即类中没有非静态(non-static)数据成员变量,没有虚函数(virtual function),也没有虚基类(virtual base class)。
1 | class hack{ |
可以看到结果是1.
其实也是因为C++标准规定,凡是一个独立的(非附属)对象都必须具有非零大小。
不然这个类创建多个对象的时候,这几个不同的对象的内存地址是一样的不是很荒唐吗
1 | hack h1, h2; |
切成release模式才会相邻,debug可能还有啥没优化的挡着了。
构建class文件
vs的操作流程吧,因为类可能单独写在一个文件[一个源文件+一个头文件]里
就会得到一个源文件和一个头文件,这里Class类名以Hack举例
1 | //Hack.cpp |
1 | //Hack.h |
然后可以用main.cpp 引入Hack的头文件,这样就能访问类。
1 |
|
1 |
|
这样函数的定义部分也可在源文件操作。除了内联函数以外,我们尽量将内联函数写在头文件中,毕竟这个内联的简易的话它是直接拿来替换的,没必要让他翻几个文件再替换。
重写原则
因为函数可以只先声明,而后定义,所以最后参考的是定义部分
1 |
|
1 |
|
其实本质上是要注意默认参数的情况,虽然我们形参习惯放于函数声明的部分。
但是默认参数其实也可以放在声明的地方。
当默认参数放在声明部分时,定义的时候就不可以再重复出现默认参数了,否则会产生错误。
所以原则上:
- 当定义和声明分开时,参数的默认值就尽量放在声明
- 定义和声明不分开的时候,就老老实实放着就行了。
this
1 |
|
如果只在此处初始化的话其实跟hp=200;
差别不大。
但是this的意义肯定不在于此,不然早就被废弃了。
this指针是一个自动生成、自动隐藏的成员,当一个对象被实例化时,this指针自动指向对象的首地址
比如说比较两个对象的某个参数,然后返回指针。
1 |
|
1 |
|
如果说没有this指针,就不好确定比较的对象的地址。
1 | int main(){ |
这样返回的还是一个指针,我们可以去接受它做其它有意义的事情。
还有就是比如说传值初始化的时候this可以区分出来
1 | void Hack::setHp(int hp){ |
当形参名没有考究,跟类的成员名一样的时候,其实就给编译器整活了。但是你加上this的话就一目了然
1 | void Hack::setHp(int hp){ |
this还有一种套娃用法。
1 |
|
1 |
|
1 | int main(){ |
会发现可以连起来用。因为它的返回值是this指针,所以当ha开始调用的时候,只要后面的参数也返回的this指针就可以一直套娃套下去。这一种就像类的连续初始化版~
当然还是要归功于引用这一特性,如果没有引用,就没法返回一个解引用之后还原成this的指针。
不能返回指针,而是返回类的话,是会存在大量的内存消耗的一个问题。
就跟结构体那会提到的类似,返回一个结构体和返回一个结构体指针肯定是不一样的,返回结构体指针还原出本身,和新建临时对象返回。
结语
熟悉下定义类的成员函数定义方式,和this指针的巧妙运用。