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

  • Post author:
  • Post category:其他




类基础

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

  • 类的构成包含成员变量、成员函数。当然,类中有很多特殊的成员函数。
  • 访问类的成员,如果是类的对象,就使用“

    对象名.成员名

    ”来访问。如果是指向这个对象的指针,则使用“

    指针名 -> 成员名

    ”来访问。
  • 类中

    public

    修饰的成员可供外界调用,

    priviate

    修饰的成员只能类的内部调用。

    class

    默认是

    private

在C中称呼“结构”,在C++中仍然可以称呼“结构”,当然也可以称呼“类”。

struct

(结构)是成员默认为

public



class

(类)。


举例说明:(这里采用定义和实现分别放在.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{}); // 可以,显示转换,生成临时对象,调用无单数构造函数



版权声明:本文为a_smart_boy原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。