转换函数(C++)的意义是什么
What is the significance of conversion function (C++)
我发现了转换函数的概念。这是同时使用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函数可以实现同样的意义?
谢谢。
转换运算符(不带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()
getter/setter和转换运算符有不同的用途:
-
访问器用于使对私人成员的访问成为公共的。通过只定义一个,您可以实现公共写入或读取访问,而无需将另一个公开。
-
转换运算符用于将整个对象转换为不同的类型。
IMHO,你不应该经常这样做:访问器是一种代码气味,类只不过是一个数据结构,这不是OOP(尽管大多数人没有意识到他们实际上在定义一个公共成员)。
转换运算符的问题是,它们使代码不太容易理解,因为转换在调用代码中不可见。而且,与转换构造函数(只接受一个参数的构造函数)结合使用,它们很容易导致大量"转换是模糊的"编译器错误。
通常,您想要编写的唯一转换运算符是到bool的转换,回答实例是否从根本上可用的问题。这样你就可以写这样的代码:
if(myInstance) {
//do something sensible
} else {
//handle error
}
在这种特殊情况下,它非常无用。
我最近写了一些处理像素的代码,它使用转换函数从每个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;
}
首先,转换运算符提供了一个不那么冗长的sintax。我是唯一一个讨厌Java get/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)被隐式转换为布尔值,以在读取操作后检查cin
的状态。
C++11提供了显式转换运算符,它不允许潜在的混淆隐式转换。只有当程序员以明确的方式指定转换时,才允许进行转换。
最后,C++常见问题解答有一篇文章,里面有一个很棒的描述、规则和在C++中重载运算符时要遵循的技术,包括转换运算符。
它不那么冗长。可能会让更加困惑。
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 是什么让放置新调用对象的构造函数?
- 重载运算符的范围是什么?它是否会影响作为类成员的集合的插入函数?
- 在函数中拥有函数原型的目的是什么?
- 使用基类指针调用基类的值构造函数的语法是什么?
- C++:使用方法调用析构函数的顺序是什么?
- 将此布尔值传递给此函数的最有效方法是什么?
- * 和 ** 在 C++ 函数声明中是什么意思?
- C++:Lambda 函数指针转换的用例是什么?
- C++关于指针和使用函数将它们启动到堆的行为究竟是什么?
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- 在将函数声明为友元时,尖括号的含义是什么?
- 在模板类之外定义友元函数的正确方法是什么?
- 在使用包含冒号的类似函数的宏时,是什么导致了这种编译器差异?
- 具有相同特征的两个对象是否只在内存中存储一次?无论定义它们的函数是什么,都是不同的
- 这里的字符串函数是什么意思
- 传递 lambda 函数的权衡是什么?
- 在C 中,对2D数组的增量是什么?函数断言(0)做什么?