41、转换构造函数(上)

1、再论类型转换

  • 标准数据类型之间会进行隐式类型转换
  • 转换规则如下
    在这里插入图片描述
#include <iostream>
using namespace std;
int main()
{
	short s = 'a';
	unsigned int ui = 1000;
	int i = -2000;
	double d = i;
	cout << d << endl;

	if (ui + i > 0)       //默认转换成unsigned int类型进行运算,结果大于0
	{
		cout << "Postive" << endl;
	}
	else
	{
		cout << "Negative" << endl;
	}
	cout << ui + i << endl;
	cout << sizeof(s + 'c') << endl;
	return 0;
}

在这里插入图片描述
其实这个程序在C语言里面都写过,第12条语句会默认转换成unsigned int类型进行运算,结果大于0。那上面那个 ui + i 的结果是怎么算的呢?这两个会先转换成无符号数,-2000用补码表示,1000用原码表示,两个相加刚好就是232-1000,就是上面那个数的值。后面那个sizeof()里面主要用到的是整形提升的原理,低于int运算会先转换成int运算。

2、提出问题

普通类型与类类型之间能否进行类型转换?类类型之间能否进行类型转换?先试验一下

#include <iostream>
using namespace std;
class Test
{
};
int main()
{
	Test t;
	t = (Test)5;
	
	return 0;
}

在这里插入图片描述
很明显,这样写普通类型与类类型之间就不能进行类型转换。如果在类里面添加构造函数呢?

#include <iostream>
using namespace std;
class Test
{
private:
	int i;
public:
	Test(int i = 0)
	{
		this->i = i;
	}
};
int main()
{
	Test t;
	t = Test(5);
	t = 5;
	return 0;
}

在这里插入图片描述
编译竟然通过了,第17条和第18条语句竟然都是对的,竟然真的把普通类型转换成类类型,真的太不可思议的。当我们不写构造函数,编译通不过,但是当我们写了构造函数,编译竟然通过了,这是为什么?

3、再论构造函数

  • 构造函数可以定义不同类型的参数
  • 参数满足下列条件时称为转换构造函数
    — 有且只有一个参数
    — 参数是基本类型
    — 参数是其它类类型

4、编译器的行为

  • 旧式的C方式强制类型转换
int i;
Test t;

i = int(1.5);
t = Test(100);
  • 编译器会尽量让源码通过编译
Test t;
t = 100;

100这个立即数默认为 int 类型,怎么可能赋值给 t 对象呢!现在就报错吗?不急,我看看有没有转换构造函数!OK,发现Test 类中定义了Test(int i),可以进行转换,默认等价于 t = Test(100)。

#include <iostream>
using namespace std;
class Test
{
private:
	int i;
public:
	Test(int i = 0)
	{
		this->i = i;
	}

	Test operator + (const Test& obj)
	{
		Test ret(i + obj.i);
		return ret;
	}
	int getI()
	{
		return i;
	}
};
int main()
{
	Test t;
	t = 5;
	
	Test r;
	r = t + 10;
	cout << r.getI() << endl;

	return 0;
}

在这里插入图片描述
如果第30行代码是手误加上了10,但是编译器却运行通过了,这样产生的Bug最难调试

编译器尽力尝试的结果是隐式类型转换,但是隐式类型转换会让程序以意想不到的方式进行工作,是工程中Bug的重要来源。

  • 工程中通过 explicit 关键字杜绝编译器的转换尝试
  • 转换构造函数被 explicit 修饰时只能进行显示转换
    — 转换方式
       1、static_cast<ClassName>(i);
       2、ClassName(i);
       3、(ClassName)value;          //不推荐
#include <iostream>
using namespace std;
class Test
{
private:
	int i;
public:
	explicit Test(int i = 0)
	{
		this->i = i;
	}

	Test operator + (const Test& obj)
	{
		Test ret(i + obj.i);
		return ret;
	}
	int getI()
	{
		return i;
	}
};
int main()
{
	Test t;
	t = 5;
	
	Test r;
	r = t + 10;
	cout << r.getI() << endl;

	return 0;
}

在这里插入图片描述
在转换构造函数前加上 explicit,刚刚的程序就直接报错了,所有的隐式转换都不被认可,那我们全部转成显式转换,看看会不会输出结果。

#include <iostream>
using namespace std;
class Test
{
private:
	int i;
public:
	explicit Test(int i = 0)
	{
		this->i = i;
	}

	Test operator + (const Test& obj)
	{
		Test ret(i + obj.i);
		return ret;
	}
	int getI()
	{
		return i;
	}
};
int main()
{
	Test t;
	t = Test(5);
	
	Test r;
	r = t + Test(10);
	cout << r.getI() << endl;

	return 0;
}

在这里插入图片描述
当我们我们全部转成显式转换,程序就没有问题了。

在C++里面我们做好C++的强制类型转换:

#include <iostream>
using namespace std;
class Test
{
private:
	int i;
public:
	explicit Test(int i = 0)
	{
		this->i = i;
	}

	Test operator + (const Test& obj)
	{
		Test ret(i + obj.i);
		return ret;
	}
	int getI()
	{
		return i;
	}
};
int main()
{
	Test t;
	t = static_cast<Test>(5);
	
	Test r;
	r = t + static_cast<Test>(10);
	cout << r.getI() << endl;

	return 0;
}

— 转换方式
   1、static_cast<ClassName>(i);
  在这里插入图片描述

  • 小结:
    — 转换构造函数只有一个参数
    — 转换构造函数的参数类型是其它类型
    — 转换构造函数在类型转换时被调用
    — 隐式类型转换是工程中Bug的重要来源
    — explicit 关键字用于杜绝隐式类型转换
#include <iostream>

using namespace std;

class Value
{
    
};

class Test
{
private:
    int i;
public:
    Test(int i = 0)
    {
        this->i = i;
    }
    
    Test(Value v)
    {
        
    }

    int getI()
    {
        return i;
    }

    Test operator+(const Test& obj)
    {
        Test ret;
        ret.i = this->i + obj.i;
        return ret;
    }
};

int main()
{
    Test t;
    Value v;
    t = v;

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值