构造函数
前言
构造函数也是类的成员函数,但是比较特殊。
类一共有两个特殊的函数,一个是构造函数,另一个是析构函数。
正文
初始化
1 |
|
1 | int main(){ |
在成员变量都为public属性时,可以通过这种方式顺序初始化。
打印一下看到值是正确被赋予了。
但是如果有个成员是私有的,那么这种顺序就被打乱了
1 |
|
1 | int main(){ |
1是不匹配,2是设置的参数超了。
归根结底就是类型没有对上,那么新建个类,然后给指定的参数赋值,在拷贝给这个类。
1 | int main(){ |
这种方法是可行的,因为这样的拷贝就是只带上hp的值。
打印出来也是行得通,但是这个私有的mp是肯定没法操作。
setter和getter
其实接触c++面向对象的时候前面上学学过一点java的。
就有两种方法,一种是传参 初始化私有的成员变量,一种是返回这个私有变量的值。
手写也不难
1 |
|
的的确确是能够达到这种效果的。
构造函数
如果每次都要先创建一个被拷贝的类,还有疯狂调用set和get方法,显得很麻烦。
所以就要说一下这个特殊的构造函数。
- 它属于成员函数在public:下
- 构造函数自动调用,且没有返回值
- 构造函数跟类同名
- 每个类至少有一个构造函数
所以说很特殊,但是很高级~
1 |
|
看到在实例化对象的时候和在打印参数值之前,肯定是调用了构造函数的,因为我们在构造函数里面也加了一条打印。
还有就是构造函数不止一个,说明它也可以重载
1 | Hack(int hp, int mp){ |
这里继续强调,形参名如果养成良好习惯就不要跟成员变量重复,除非你像我一样习惯用this指针去分开,否则就是一种无用行为,形参=形参编译器都傻了
为了区分也加个cout
1 | Hack(int hp, int mp){ |
可以看到效果很妙。
重载嘛,把类的对象当参数也ok,因为之前是用=
号去赋值
1 | Hack(Hack& H){ |
默认构造函数
这个就很好理解,就是你没有主动写,那么编译器自动给它加上一个类名(){}
这个默认构造函数,无参数无返回值,就是空的放在那里。
1 | class Box{ |
default
前面说到只要定义过构造函数,就不会出现默认构造函数,但有的时候可能还需要一个默认构造函数
就可以用到default关键字去声明。
类名(){}
默认构造函数类名()=default;
用关键字定义默认构造函数
当我们注释掉之前写的构造函数
1 | /*Hack(){ |
这个时候你再去创建一个类的对象就会报错了
解决的方法就是给它留个默认构造函数或者指定
1 | Hack(){ |
当然这两种方法只能存在一个,否则也是定义冲突。
这两种孰优孰劣要看默认构造函数里面是否要存放什么比如初始化,如果要就选前者,如果不需要就选后者。
explicit
被explicit关键字修饰的构造函数会被禁止类型转换
1 | bool toMax(Hack hack){ |
布尔值,返回就是0或者1,这个很直观。
逻辑上也一点问题没有。
但是有个神奇的地方。
你会发现,我toMax函数明明参数是Hack类型的,居然放数字也成功了
其实本质上就是编译器偷偷转换了,因为我们有个构造函数就是让传值赋给mp的。
你在调用std::cout << ha.toMax(900) << std::endl;
他就会先把这个900传进给一个临时的hack对象,然后再用这个临时的对象去和ha作比较。
那么说去掉这个构造函数就行,也确实是一个办法,但是有的时候我这个构造函数存在有他的道理,我只是不希望他被拿来做转换运算了。就可以使用explicit这个关键字
1 | explicit Hack(int mp){ |
调用的地方就会发生报错了,无法转换。
这个在后面可以规避掉很多问题。
结语
未完结待续。