C++ 类的自动转换和强制类型装换

C++ 类的自动转换和强制类型装换

0X00 前言

在C++中,类的设计是一件十分重要的事情,一个类设计的好坏取决于它接口是否优良,即函数的设计

有时候我们可能需要设计多种多样的接口,目的是为了增强类的多态性。

今天我们来讲一讲类的转化问题

在此之前,我们来定义一个类,作为我们后面的

class Dog
{
    
    
privateint GoOutTimes;  //表示一周遛狗的次数
   double Kilo;		//表示一周遛狗走的公里数
   double Time;		//表示一周遛狗的时间
public:
	Dog(double ti);  //构造函数:初始化遛狗时间
	Dog(int times,double ki);   //构造函数:初始化遛狗次数与遛狗距离
	Dog();		//默认构造函数Dog();	//析构函数

	void show_Ki() const;  //展示公里数
	void show_ti() const;  //展示时间
}

0X10 初始化化时的自动转换

1、利用构造函数的隐式转换
可以看到,上面的类提供了三个构造函数:

    Dog(double ti);  
	Dog(int times,double ki);   
	Dog();		

我们可以在声明类对象的时候就调用构造函数进行初始化:

   Dog Chichi(12.6);
   Dog Mimi(3,10.2);
   Dog Lolo();

因为一个Dog对象表示一个狗狗的一周外出情况(天数,公里数以及时间),那么我们是否可以提供一些将整数或者浮点数转化为Dog对象的方法

由于我们拥有对应的构造函数:
Dog(double ti);
因此我们就可以利用构造函数将double类型转化为 Dog 类型。是不是有点不可思议?

然而它的确是可以工作的

Dog myDog;
myDog=14.3;

当程序运行到 myDog=14.3; 时,编译器会去检查构造函数中是否有 Dog(double) 这样的构造函数,既然存在,那么就用 Dog(double) 来创建一个 临时的 Dog 对象,然后采用逐个成员赋值的方式将该临时对象复制到 myDog 中, 这一过程叫做 隐式转换 ,因为这是自动进行的。

有一点我们需要特别注意
只有接受一个参数的构造函数才能作为转换函数

也就是说 Dog(int times,double ki); 函数是不能用来进行转换的,除非它能给第二个参数提供默认值

Dog(int times,double ki=8.9); 

这时候才能用户转换 int

2、explicit 限定下的显式

但是有时为了保证安全性,又必须阻止这种不安全的行为发生。(是不是听起来比较矛盾,但这正是语言设计者需要考虑的事情)

也就是说关闭这种隐式转换

因此引进 explicit(显式的) 限定词,在它的修饰下,表示对于修饰的函数,这样的隐式转换将不起作用:

explicit Dog(double ti);  

此时,上面的 隐式转换将不起作用,但是依旧可以用显式转换来进行强制转换:

Dog myDog;
//error
myDog = 13.2 
//right
myDog = Dog(13.2);
myDog = (Dog) 13.2;

3、小结

来总结一下刚才所讲的内容:
在使用了 explicit 关键字后,Dog (double) 只能用于 显式强制类型转换;
否则,还可以用于以下隐式转换:

  • 将Dog 对象初始化为 double 值时

  • 将double 值传递给 Dog对象时

  • 将double值传递给接受Dog参数的函数时

  • 返回值被声明为Dog的函数并试图返回double值时

  • 在上述任意情况下,使用可转化为double类型的内置类型时

    可能最后一点,大家不太明白。
    我们来举个例,就拿最上面的类,因此存在 Dog(double ti); 构造函数,所有我们知道,将double转化为 Dog类型是可以的:

Dog myDog;
myDog = 14.5;

然而其实下面的代码也是可以的:

Dog myDog;
myDog = 14;

其实也是很好理解的 因为 int (14)型是可以转化为 double(14.0) 型的,因此这样是合法的。

但是我们也应特别注意的是:二义性问题

什么意思呢?

假如我们Dog类中还有这样一个函数 Dog(long) ,那么 myDog=14 的转化将是无效的!

因为 int 既可以转化为 double 也可以转化为 long ,那么此时就出现了让编译器为难的 二义性问题。

那么编译器就罢工喽。

0X11 自定义转换函数

上面我们讲到了可以将 基本类型(如 double) 转换为我们的类对象,前提是有相对应的构造函数。

那么,能否直接将类对象转换为 基本类型 呢?(听起来又是个很奇特的想法),就像这样:

Dog Nana(7.6);
double Time=Nana;

答案是可以的!

但是,这时候我们需要的就不是构造函数,而是 一种特殊的运算符函数——转换函数

那么如何创建转换函数呢?
假设我们要转换为typeName类型,需要使用这种形式的转换函数:
operator ypename ()
注意以下几点:

  • 转换函数必须是类方法;

  • 转换函数不能指定返回类型;

  • 转换函数不能有参数;

    现在我们将 Dog 对象转换为 int 和 double 类型的函数添加到类的声明当中:

class Dog
{
    
    
privateint GoOutTimes;  //表示一周遛狗的次数
   double Kilo;		//表示一周遛狗走的公里数
   double Time;		//表示一周遛狗的时间
public:
	Dog(double ti);  //构造函数:初始化遛狗时间
	Dog(int times,double ki);   //构造函数:初始化遛狗次数与遛狗距离
	Dog();		//默认构造函数Dog();	//析构函数

	void show_Ki() const;  //展示公里数
	void show_ti() const;  //展示时间

	operator int() const;	//转换为 int
	operator double() const;  //转换为 double

函数的实现内容则可以自己规定:

//将遛狗天数返回加1
Dog::operator int() const
{
    
    
	return GoOutTimes+1;
}

//返回一周遛狗平均公里数
Dog::operator double() const
{
    
    
	return Kilo/7;
}

0X20 后言

C++为了拓展类的多态性,提供了很多设计类的方法,如果我们能很好的运用,那么对我们的编码工作将是很好的帮助。

希望今天的内容能对大家有所帮助~

谢谢大家~

来日再见!

————————————————————————————————————————————————————————
参考:《C++ primer Plus 第6版》

猜你喜欢

转载自blog.csdn.net/rjszz1314/article/details/104526762
今日推荐