1

我遇到了转换函数的概念。这是同时使用 getter 和转换函数的示例代码。

#include<iostream>

using namespace std;

class conv
{
  int val;
  int a,b;

  public:

  conv(int x, int y)
  {
    a = x;
    b = y;
    val = 1;
    val = a*b;
  }

  int get(){ return val; };

  operator int(){ return val; };

};

int main()
{
  conv obj(1,2);
  int x;

  x = obj; // using conversion function

  cout<<"Using conversion function"<<x;

  cout<<"Using getters"<<obj.get();

  return 0;
 }

两个 cout 语句产生相同的输出。我想知道转换函数相对于 getter 函数的特殊意义是什么,因为 getter 函数可以实现相同的功能?

谢谢。

4

5 回答 5

2

转换运算符(不带explicit关键字)的主要目的是提供类型到目标类型的隐式转换。这意味着(例如)如果您有一个采用目标类型的函数(在您的示例中为 an int):

void function (int value) {...}

然后您可以传递您的类型的实例,编译器将隐式调用转换运算符以调用函数:

// your code:
conv obj(1,2);
function(obj); // compiler will call conv::operator int()

在我从事的大多数项目中,使用这些是不受欢迎的,因为使用 C++ 的这个特性会使你的代码更难遵循。

explicit关键字通知编译器不允许隐式转换(C++ 11 之前,这仅适用于转换构造函数)。在这种情况下,您必须显式转换对象:

// your code:
conv obj(1,2);
function(static_cast<int>(obj)); // compiler will call conv::operator int()
于 2013-08-31T11:15:03.990 回答
2

getter/setter 和转换运算符有不同的用途:

  1. 访问器用于使对私有成员的访问成为公共的。通过只定义一个,您可以在不公开另一个的情况下实现公共写入或读取访问。

  2. 转换运算符用于将整个对象转换为不同的类型。

恕我直言,您不应该经常这样做:访问器是一种代码气味,该类只不过是一种数据结构,而不是 OOP(尽管大多数人没有意识到他们实际上是在定义一个公共成员)。

转换运算符的问题是它们使代码不太容易理解,因为转换在调用代码中不可见。而且,结合转换构造函数(构造函数只接受一个参数),它们很容易导致大量的“转换是模棱两可的”编译器错误。

通常,您想要编写的唯一转换运算符是转换为 bool,回答了实例是否从根本上可用的问题。这样你就可以编写如下代码:

if(myInstance) {
    //do something sensible
} else {
    //handle error
}
于 2013-08-31T12:42:54.003 回答
1

在这种特殊情况下,它非常无用。

我最近写了一些代码来操作像素,它使用一个转换函数从每个 R、G、B、A 值的 8 位中生成 16 位像素。

class Pixel
{
    uint8_t a, r, g, b;

public:
    Pixel() : a(0xff), r(0), g(0), b(0) {};
    Pixel(uint8_t aA, uint8_t aR, uint8_t aG, uint8_t aB) : a(aA), r(aR), g(aG), b(aB) {}
    Pixel(uint16_t rgb16) 
        {
            a = 0xff;
            r = ((rgb16 >> 11) & 31) << 3;
            g = ((rgb16 >> 5)  & 63) << 2;
            b = (rgb16 & 31) << 3;
        }

    Pixel(uint32_t argb32)
        {
            a = argb32 & 0xff;
            r = (argb32 >> 8) & 0xff;
            g = (argb32 >> 16) & 0xff;
            b = (argb32 >> 24) & 0xff;
        }
    uint8_t A() const { return a; }
    uint8_t R() const { return r; }
    uint8_t G() const { return g; }
    uint8_t B() const { return b; }

    void A(uint8_t aA) { a = aA; }
    void R(uint8_t aR) { r = aR; }
    void G(uint8_t aG) { g = aG; }
    void B(uint8_t aB) { b = aB; }

    operator uint16_t() 
        { 
            return ((r >> 3) << 11) |
                ((g >> 2) << 6) |
                (b >> 3); 
        }
};

它允许使用此代码的代码像这样工作:

uint16_t *frame_buffer;
...

for(...)
{
     ... 
     Pixel blended = Blend(above, below);
     frame_buffer[y * ScreenWidth + x] = blended;
}
于 2013-08-31T11:18:09.197 回答
1

首先,转换运算符提供了一种不太冗长的语法。我是唯一讨厌 Javaget/set语法的人吗?
Bt 此功能的主要目的是提供您自己的类型和指定类型之间的转换。这在以下情况下非常有用:

  • 到基本数字类型的转换是自然而有用的。例如:

    class fixed_point
    {
    private:
        long long int _bits;
    
    public:
        fixed_point(float number); //Cast from floating-point
        operator float(); //Cast to floating-point
    };
    

    请注意,此功能很容易被过度使用,依赖于令人困惑和非自然的情况。例如:

    struct complex_number
    {
        float real , imaginary;
    
        operator float(); //WTF!!! What is this? Real part? Imaginary part?
    };
    

    事实上,任何人都可能认为使用命名构造函数和 getter 可以使“有用”的情况更具可读性:

    class fixed_point
    {
    private:
        long long int _bits;
    
        fixed_point(long long int bits) _bits( bits ) {}
    
    public:
        static fixed_point from_floating_point(float number);
               float       to_floating_point();
    };
    
  • 对象状态标志:提供布尔转换以检查对象的状态(OK 与 ERROR)。例如,这就是标准库流所做的

    while( cin >> input )
    {
        ...
    }
    

    之所以有效,是因为流operator>>以实现流畅接口的方式实现,也就是说,允许连接操作,例如:

    cout << "hello" << "world";
    

    流运算符的实现返回对传递给运算符的同一流的引用,即:

    istream& operator>>(istream& is , INPUT_TYPE input)
    {
        /* read ops */
        return is;
    }
    

    因此,当您执行while(std::cin >> input)该语句时cin >> input,它调用了一个重载,operator>>该重载返回一个对 的引用std::cin,并且该对象 (cin) 被隐式转换为一个 boolean,以检查cin读取操作后的状态。

C++11 提供了显式转换运算符,它不允许潜在的混淆隐式转换。只有当程序员以明确的方式指定它时,才允许进行这种转换。

最后,C++ 常见问题解答中有一篇很棒的描述、规则和在 C++ 中重载运算符时要遵循的技术,包括转换运算符

于 2013-08-31T11:56:07.387 回答
0

它不那么冗长。并且可能更令人困惑。

于 2013-08-31T11:07:12.533 回答