我遇到了转换功能的概念。这是使用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函数可以实现同样的效果吗?
感谢。
答案 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和转换运算符有不同的用途:
访问者用于访问私有成员public。通过仅定义一个,您可以实现公共写入或读取访问,而不会将另一个公开。
转化运算符用于将整个对象转换为其他类型。
转换运算符的问题在于它们使代码不易跟踪,因为转换在调用代码中不可见。并且,与转换构造函数(构造函数只采用一个参数)相结合,它们很容易导致大量“转换是模糊的”编译器错误。
通常,您想要编写的唯一转换运算符是转换为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)
它不那么冗长。 可能更令人困惑。