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

参考

C++ Primer Plus (第6版)

类自动转换

接受一个参数的构造函数允许使用赋值语法将对象初始化一个值

Classname object = value;
等价于
ClassName object(value);
等价于
ClassName object = ClassName(value);

只有接受一个参数的构造函数才能作为转换构造函数(某类型->类)

#include <iostream>

class Test{
private:
	int m_a;
	double m_b;
public:
	Test();
	Test(double b);         		// 可作为转换构造函数
	// Test(int a, double b = 0);	// 可作为转换构造函数
	Test(int a, double b);  		// 不可作为转换构造函数
  	Test(const Test& t);
  	Test& operator=(const Test& t);
	friend void Display(const Test& t, int n);
};

Test::Test(){
  std::cout << "构造 Test()" << std::endl;
	m_a = 0; m_b = 0;
}

Test::Test(double b){
  std::cout << "构造 Test(double)" << std::endl;
	m_a  = 0;
	m_b = b;
}

Test::Test(int a, double b){
  std::cout << "构造 Test(int, double)" << std::endl;

	m_a  = a;
	m_b = b;
}

Test::Test(const Test& t){
  std::cout << "复制构造 Test(const Test&)" << std::endl;
  m_a = t.m_a;
  m_b = t.m_b;
}

Test& Test::operator=(const Test& t)
{
  std::cout << "operator=" << std::endl;
   if(this == &t)
   {
     return *this;
   }

   m_a = t.m_a;
   m_b = t.m_b;
   return *this;
}

void Display(const Test& t, int n){
	for(int i = 0; i < n; i ++){
		std::cout << t.m_a << "," << t.m_b << std::endl;
	}
}
int main(){
	Test test(10);        // int 转为 double, 使用Test(double b)
  	std::cout << "---------" << std::endl;
	test = 12;			  // int 转为 double, 使用Test(double b)
  	std::cout << "---------" << std::endl;
	Test test1 = 11;      // int 转为 double, 使用Test(double b)
  	Test test2 = test1;
	Display(422, 2);	  // 遇到int类型, 找不到Test(int a), 寻找其它内置类型(int可以转换)的构造函数, Test(int b) 满足要求
	return 0;
}

在这里插入图片描述

注意, 当且仅当转换不存在二义性时, 才会进行转换, 如果这个类还定义了构造函数Test(long), 则编译器会报错

explicit 可以关闭隐式转换

explicit Test(double b);    // 不支持隐式转换

类强制转换

自动转换把 某类型 转成 类
强制转换把 类 转成 某类型, 需要用到特殊C++运算符函数, 转换函数
转换函数 是 用户定义的强制类型转换, 可以显示和隐式的调用(类->某类型)

Test t(10.2);
double a = double (t);
double b = (double) t;

Test tt(10, 3);
double aa = tt;     // 隐式转换, 编译器会查看是否定义于此匹配的转换函数, 没有则生成错误消息

转换函数

operator typeName(); // typeName 是要被转换的类型

注意:
- 必须是类方法
- 不能指定返回类型
- 不能由参数

#include <iostream>

class Test{
private:
	int m_a;
	double m_b;
public:
	Test();
	Test(double b);         	
	Test(int a, double b);  	
  
	 // 转换函数
	 operator int() const; 
	 operator double() const;
};

Test::Test(){
	m_a = 0; m_b = 0;
}

Test::Test(double b){
	m_a  = 0;
	m_b = b;
}

Test::Test(int a, double b){
	m_a  = a;
	m_b = b;
}

Test::operator double() const {
  return m_a + m_b;
}

Test::operator int() const{
  return int(m_a + m_b+ 0.5);
}

int main(){
	Test test(9, 2.8);
  	double p = test;
  	cout << "转换成double = " << p << std::endl;
  	cout << "转换成int = " << int(test) << std::endl;
	long g = (double) test;  // 使用double 转换
	long gg = int(test)      // 使用int 转换
}

在这里插入图片描述
转换函数有时候也不需要隐式转换

int ar[20]
...
Test t(120, 2); // 这个Test只有一个转换函数operator int(), 不然ar[t] 这里转换会有二义性
...
int T = 1;
...
cout << ar[t] << endl;   // 写错的地方

原本是要把T作为数组索引, 不小心写错了, 写成对象t, Test类定义了operator int() , 会把转换成122, 作为数组索引, 然后就导致越界
原则上最好使用显示转换, 避免隐式转换
C++98 explicit不能用于转换函数, C++11消除这个限制

class Test{
...
	explicit operator int() const;
	explicit operator double() const;
};

也可以用功能相同的非转换函数替换转换函数, 仅在显示调用

class Test{
...
	int Test_to_int() const {return int(a + b);}
};

总结

  • 只有一个参数的类构造函数 用于类型于参数相同的值 -> 类类型, 构造函数声明中使用explict可防止隐式转换, 只允许显示转换
  • 转换函数是特殊的类成员运算函数, 可将 类 -> 其它类型, 是类成员, 没有返回值, 没有参数, 名为operator typeName(), C++11可以用explict防止隐式转换, 只允许显示转换

转换函数与友元函数

没有转换函数和构造转换函数的Test类重载加法运算符, 重载同一运算符成员函数和友元函数不能都提供


// 成员函数
Test test::operator+(const Test& s) const {
	Test t(m_a + m_b + s.m_a + s.m_b);
	return t;
}

// 友元函数
Test operator+(const Test& t1, const Test& t2) const {
	Test t(t1.m_a + t1.m_b + t2.m_a + t2.m_b);
	return t;
}

第一种情况: a 和 b 都是类

Test a(9, 12);
Test b(12, 8);
Test t;
t = a + b; 
// Test类用的是 成员函数 的话
// t = a + b     ---转换--->       t = a.operator+(b)
// Test类用的是 友元函数 的话
// t = a + b     ---转换--->       t = operator+(a, b)         

这个 成员函数, 友元函数 都可以实现

现在给Test类提供Test(double)构造转换函数
第二种情况: a是类, b不是类, a在前面

Test a(9, 12);
double b = 13.6;
Test t;
t = a + b;
// Test类用的是 成员函数 的话
// t = a + b     ---转换--->       t = a.operator+(Test(b))
// Test类用的是 友元函数 的话
// t = a + b     ---转换--->       t = operator+(a, Test(b))   

这个 成员函数, 友元函数 都可以实现

第三种情况: a是类, b不是类, b在前面

Test a(9, 12);
double b = 13.6;
Test t;
t = b + a;
// Test类用的是 成员函数 的话  不行, 因为b.operator+()的参数要double类型
// Test类用的是 友元函数 的话
// t = b + a     ---转换--->       t = operator+(Test(b), a))   

这个只有 友元函数 都可以实现
要成员函数也可以实现, 可以再加一个友元函数

Test operator+(double x);   // 成员函数, 满足 Test + double
friend Test operator+(double x, Test& t); // 友元函数, 满足 double + Test
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值