类_构造函数、构造函数初始化列表、函数默认参数、隐式转换和explicit

类基础

类是一种自定义的数据类型,也就是一个新类型。类与类之间,并不是彼此孤立的。例如,一个类可以派生出子类,那么这个派生子类的类就变成了该子类的父类。

  • 类的构成包含成员变量、成员函数。当然,类中有很多特殊的成员函数。
  • 访问类的成员,如果是类的对象,就使用“对象名.成员名”来访问。如果是指向这个对象的指针,则使用“指针名 -> 成员名”来访问。
  • 类中public修饰的成员可供外界调用,priviate修饰的成员只能类的内部调用。class默认是private

在C中称呼“结构”,在C++中仍然可以称呼“结构”,当然也可以称呼“类”。struct(结构)是成员默认为publicclass(类)。


举例说明:(这里采用定义和实现分别放在.h头文件和.cpp源文件中)
.h头文件

#ifndef _TIME_H
#define _TIME_H
class time
{
public:
	unsigned Hour;
	unsigned Min;
	unsigned Sec;
private:
	unsigned MillTime;
public:
	void unsigtime(unsigned H,unsigned M,unsigned S);
private:
	void unsigmilltime(unsigned Mill);
};
#endif // !_TIME_H

.cpp源文件

#include"time.h"
//这两个冒号叫 作用域运算符,表示unsigtime函数属于time类。避免多个类中相同的函数无法分别
void time::unsigtime(unsigned H, unsigned M, unsigned S)	
{
	Hour = H;
	Min = M;
	Sec = S;
	unsigmilltime(7);
}
void time::unsigmilltime(unsigned Mill)		
{
	MillTime = Mill;
}

对象复制

  1. time mytime1 = mytime;
  2. time mytime2(mytime);
  3. time mytime3{mytime};
  4. time mytime4 = {mytime};
  5. time mytime5;
    mytime5 = mytime; // 通过赋值操作来复制对象

构造函数

  • 在类中有一种特殊的成员函数,它的名字和类名相同,在创建对象的时候,这个特殊的成员函数会被自动调用,这个成员函数叫作“构造函数”。
  • 构造函数无返回值。在构造函数的函数头什么也不写。
  • 不可手工调用构造函数,否则编译器报错。
  • 正常情况下 ,构造函数应被声明称public,因为创建一个对象时,系统要调用构造函数。
  • 构造函数中如果有参数,则创建对象时也要指定相应的参数。

举例说明:
在.h头文件中声明一个public类型的构造函数:
public:
time(int tmp_H,int tmp_M,int tmp_S);

在.cpp源文件中实现这个构造函数:
time::time(int tmp_H,int tmp_M,int tmp_S) // 函数体内赋值
{
Hour = tmp_H;
Minture = tmp_M;
Second = tmp_S;
unsigmilltime(7);
}


构造函数的初始化列表

在.cpp源文件中亦可使用下方构造函数的实现的方式。
time::time(int tmp_H,int tmp_M,int tmp_S)
:Hour(tmp_H),Minture(tmp_M),Second(tmp_S) // 这就叫做构造函数的初始化列表
{ }

上述两种构造函数的实现,第一个叫做赋值,第二个叫做初始化。构造函数初始化列表写法更显得专业。对内置类型如int类型的成员变量,使用两种方式来初始化差别并不大。但对于类类型的成员变量,使用初始化列表的方式初始化比使用赋值语句初始化效率更高。
同时需要避免写出如下的构造函数的初始化列表。
time::time(int tmp_H,int tmp_M,int tmp_S)
:Hour(tmp_H),Minture(Hour),Second(Minture) // 谁先有值,谁后有值是一个问题,会出现值不确定的情况
{ }
要注意的是:某个成员变量的值不要依赖于其他成员变量(如Minture(Hour)),因为成员变量的给值程序并不是根据初始化列表中从左到右的顺序,而是依据类定义中成员变量的定义顺序(从上到下的顺序)

多个构造函数

  • 一个类中可以有多个构造函数,如果有多个构造函数,就为该类对象的创建提供了多种创建方法。但这些构造函数总要有写区别,如参数数量或者参数类型上的区别。

下面再声明一个单参数的构造函数:
在.h头文件中声明一个public类型的构造函数:
public:
time(int tmp_H);
在.cpp源文件中实现这个构造函数:
time::time(int tmp_H) // 函数体内赋值
{
Hour = tmp_H;
Minture = 7;
Second = 7;
unsigmilltime(7);
}

函数默认参数

更改在.h头文件中构造函数的声明。将第三个参数的默认值改为7.
public:
time(int tmp_H,int tmp_M,int tmp_S = 7);
此时tmp_S参数就叫作函数默认参数。在创建类对象时,如果不给改参数赋值,则该参数的默认值就是7。

任何函数都可以有默认参数,对于传统函数,默认参数一般放在函数的声明中,而不放在函数的实现中,除非改函数没有声明只有定义。即一般写在.h头问价中。
默认参数必须出现在非默认参数的右侧。
同时也要避免以下构造函数的问题:
public:
time(int tmp_H,int tmp_M,int tmp_S = 7);
time(int tmp_H,int tmp_M); // 在创建类对象时,系统不知道该调用哪一个

隐式转换和explicit

当声明一个单参数的构造函数时。

在.h头文件中声明一个public类型的构造函数:
public:
time(int tmp_H);
在.cpp源文件中实现这个构造函数:
time::time(int tmp_H) // 函数体内赋值
{
Hour = tmp_H;
Minture = 7;
Second = 7;
unsigmilltime(7);
}

下面两种类对象的创建无语法错误。(没有单参数的构造函数时,下面两种类对象创建均会报错)
time mytimesig = 7
time mytimesig1 {1,2,3,4} // 最后一个参数当做参数传递进去

再看一下下面的一个普通函数:
void sigfun(time T)
{
return ;
}
现在发现,用一个数字就可以调用该函数。
sigfun(7); // 这里调用了time类中的单参数构造函数
上述说明一个现象是,系统自动完成了一个行为——从数字到对象的转换。即数字自动转换成了类对象。这种转换称为隐式转换或简称隐式类型转换

此外,接着上述代码继续书写,如下代码也是调用了time类的单参数构造函数。
mytimesig2 = 7; // 生成一个临时对象,把临时对象的值复制到了mytimesig2中
time mytimesig3 = {7}; // 这种写法正常,明确告诉系统调用带一个参数的构造函数
time mytimesig4 = 7; // 代码比较含糊,存在临时对象或者隐式转换的问题

当然,对上述问题,可以强制系统不做隐式转换。这就需要在函数声明中加上explict(显示),则这个构造函数只能用于初始化和显示类型转换。
具体如下:
public:
explicit time(int tmp_H);
此时,time mytimesig3 = {7};会报错。而time mytimesig3{7};能够成功创建对象。这说明了一个问题:有了这个等号,就变成了一个隐式转换(其实是构造并初始化),省略这个等号,就变成了显示初始化(也叫直接初始化)
同样,下面的写法也会报错。
mytimesig2 = 7;
time mytimesig4 = 7;
sigfun(7);
那如何修改呢?
mytimesig2 = time(7);
time mytimesig4 = time(7); // 或者 time{7}
sigfun(time(7));
一般来说,单参数的构造函数都声明为explicit。当然,explicit也可以用于无参数或者多个参数的构造函数。
如:
public:
explicit time();

sigfun({}); // 不可以,隐式转换了
sigfun(time{}); // 可以,显示转换,生成临时对象,调用无单数构造函数

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值