转换函数的意义是什么(C ++)

时间:2013-08-31 11:04:46

标签: c++

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

#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函数可以实现同样的效果吗?

感谢。

5 个答案:

答案 0 :(得分:2)

转换运算符的主要用途(没有explicit关键字)是提供类型到目标类型的隐式转换。这意味着(例如)如果您有一个采用目标类型的函数(在您的示例中为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()

答案 1 :(得分:2)

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

  1. 访问者用于访问私有成员public。通过仅定义一个,您可以实现公共写入或读取访问,而不会将另一个公开。

  2. 转化运算符用于将整个对象转换为其他类型。

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

    转换运算符的问题在于它们使代码不易跟踪,因为转换在调用代码中不可见。并且,与转换构造函数(构造函数只采用一个参数)相结合,它们很容易导致大量“转换是模糊的”编译器错误。

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

    if(myInstance) {
        //do something sensible
    } else {
        //handle error
    }
    

答案 2 :(得分: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;
}

答案 3 :(得分:1)

首先,转换运算符提供了更简洁的sintax。我是唯一一个讨厌Java get/set语法的人? 此功能的主要目的是提供您自己的类型和指定类型之间的转换。这在以下情况下非常有用:

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

    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?
    };
    

    事实上,任何人都可以认为使用named constructor idiom和吸气剂可以更有效地阅读“有用”案例:

    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 vs ERROR)。例如,这就是Standard Library streams do

    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)为< strong>隐式转换为布尔值,以便在读取操作后检查cin的状态。

C ++ 11提供了explicit conversion operators,它不允许这种可能令人困惑的隐式转换。只有程序员以明确的方式指定转换时才允许进行转换。

最后,C ++ FAQ has a post在使用C ++重载运算符时需要遵循一些很棒的描述,规则和技术,conversion operators included

答案 4 :(得分:0)

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