第11章 使用类——类型转换(二)将自定义类型转换为内置类型

本文章是作者根据史蒂芬·普拉达所著的《C++ Primer Plus》而整理出的读书笔记,如果您在浏览过程中发现了什么错误,烦请告知。另外,此书由浅入深,非常适合有C语言基础的人学习,感兴趣的朋友可以自行阅读此书籍。

上一节我们可以利用构造函数,将内置类型(double)转换为自定义类型(Stonewt),那么问题来了,可以将自定义类型转换成内置类型吗?

比如如下的语句:

Stonewt wolfe(285.7);
double host = wolfe;

构造函数只用于从某种类型到类类型的转换。要进行相反的转换,必须使用特殊的C++运算符函数——转换函数。

转换函数的格式如下:

operator typeName();

需注意以下几点:

  • 转换函数必须是类方法
  • 转换函数不能指定返回类型
  • 转换函数不能有参数

例如,转换为double类型的函数的原型如下所示:

operator double();

typeName(此处为double)指出了要转换成的类型,因此不需要指定返回类型。转换函数是类方法意味着:它需要类对象来调用,从而告知函数要转换的值。因此,函数不需要参数。

接下来,我们完善下Stonewt类,
类声明如下:

//stonewt1.hpp
#ifndef _STONEWT1_HPP_
#define _STONEWT1_HPP_

class Stonewt
{
private:
  enum {Lbs_per_stn = 14};
  int stone;
  double pds_left;
  double pounds;

public:
  Stonewt(double lbs);
  Stonewt(int stn, double lbs);
  Stonewt();
  ~Stonewt();
  void show_lbs() const;
  void show_stn() const;
  operator double() const;
  operator int() const;
};
#endif

类方法实现如下:

//stonewt1.cpp

#include <iostream>
using std::cout;
#include "stonewt1.hpp"

Stonewt::Stonewt(double lbs)
{
  stone = int (lbs) / Lbs_per_stn;
  pds_left = int (lbs) % Lbs_per_stn + lbs - int (lbs);
  pounds = lbs;
}
Stonewt::Stonewt(int stn, double lbs)
{
  stone = stn;
  pds_left = lbs;
  pounds = stn * Lbs_per_stn + lbs;
}
Stonewt::Stonewt()
{
  stone = pds_left = pounds = 0;
}
Stonewt::~Stonewt()
{

}
void Stonewt::show_stn()const
{
  cout << stone << " stone," << pds_left << " pounds\n";
}
void Stonewt::show_lbs()const
{
  cout << pounds << " pounds\n";
}
Stonewt::operator int() const
{
  return int(pounds + 0.5);
}
Stonewt::operator double() const
{
  return pounds;
}

使用类:

//stone1.cpp
#include <iostream>
#include "stonewt1.hpp"

using std::cout;
int main()
{
    Stonewt poppings(9, 2.8);
    double p_wt = poppings;
    cout << "Convert to double => ";
    cout << "Popings: " << p_wt << " pounds.\n";
    cout << "Convert to int => ";
    cout << "Popings: " << int(poppings) << " pounds.\n";
    return 0;
}

程序运行结果如下:

Convert to double => Popings: 128.8 pounds.
Convert to int => Popings: 129 pounds.

假设我们省略了强制类型转换,使用了如下的语句:

cout << "Popings: " << poppings << " pounds.\n";

编译器就会报出二义性错误,因为它不知道该将popings换成double还是int。但当我们删除掉operator int()转换函数后,就可以编译成功。

和转换构造函数一样,转换函数也有其优缺点。提供自动、隐式转换的函数所存在的问题是:在用户不希望进行转换时,转换函数也可能进行转换。

例如如下的代码:

int ar[20];
...
Stonewt temp(200);
...
int Temp = 1;
...
cout << ar[temp] << "!\n";

因为Stonewt定义了一个operator int(),因此Stonewt对象temp将被转换为int 200,并用做数字索引,明显会导致错误。

有两种办法防止这个问题:
1,使用explicit关键字修饰转换函数,在需要的时候使用显式强制转换。

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

2,用一个功能相同的非转换函数替换该转换函数,仅在被现实调用时,该函数才会执行。
将:

Stonewt::operator int() {return int (pounds + 0.5);}

替换为:

int Stonewt::operator Stone_to_Int() {return int (pounds + 0.5);}

这样,下面的语句将是非法的:

int plb = poppings;

但如果确实需要这种转换,可以这样做:

int plb = popings.Stone_to_Int();

应谨慎地使用隐式转换函数。通常,最好选择仅在被显式调用时才会执行地函数。

总之,C++为类提供了下面的类型转换:

  • 只有一个参数的类构造函数用于将类型与该参数相同的值转换为类类型。例如,将int值赋给Stonewt对象时,接受int参数的Stonewt类构造函数将自动被调用。然而,在构造函数声明中使用explicit可防止隐式转换,而只允许显式转换。
  • 被称为转换函数的特殊类成员运算符函数,用于将类对象转换为其他类型。转换函数是类成员,没有返回类型、没有参数、名为operator typename(),其中typename是对象将被转换成的类型。将类对象赋给typename变量或将其强制转换为typename时,该转换函数将自动被调用。
posted @ 2024-04-11 08:13  superbmc  阅读(4)  评论(0编辑  收藏  举报