运算符重载(operator overloading)只是一种”语法上的方便“(syntactic sugar).也就是说它只是另一种函数调用的方式。
运算符重载
运算符重载有成员运算符和非成员运算符之分,那么这个之间有什么区别呢,应该选择哪一种呢?
总的来说,如果没有什么差异,它们应该是成员运算符。这样做强调了运算符和类的结合。当左操作数是当前类的对象时,运算符会工作的很好。
但有的时候左侧操作数是别的类对象。这种情况通常出现在输入输出流重载operator<<和>> 时。因为输入输出流是一个基本C++库。
这里就说到了关键了。为了应付各种数据类型的输出,输入输出流的重载就很重要了。
1 | // 代码之后贴 |
这里我先暂停一下,说一说为什么要认识运算符重载这个问题。
举例来说,cout
这个类是我学C++最早接触的对象了之一了,但是却很不是理解。其实即就是cout
对<<
运算符进行了重载。
我自己创建了一个Record类,希望这个类能对接在<<
后面的数据进行一些操作,比如说接收数据什么的。1
2Record << 2;
Record << "str string";
想这样把后面的数据接收保存在类内变量中。就这样我遇见了下面的代码:1
2
3
4
5
6
7
8// 在Record类内
template<typename T>
Record& operator<<(const T& data)
{
m_message << data;
return *this;
}
代表着混沌势力的模板登场了(对我来说)。这里就涉及到了函数模板的问题。我看到上面的代码的时候第一反应是,这段代码能直接用?
答案是肯定的,像类模板的使用那样,指定明确的模板参数类型来特化函数模板使用是可行的,也就是我觉得应该这样做的,但是让编译器从函数的参数中推断出它们的类型将会更方便。
后面的内容就更多了,在别的模板章节中展开更好。
回到上面的代码,m_message << data
的m_message是什么类型合适呢?是ostringstream
。是C++标准库的东西,这样就省得自己一个一个重载数据类型了。方法是个好方法,但是最后我没用上。因为要处理宽字符的问题,涉及到宽窄字符互相转换的问题,试来试去总是出问题,我就Pass掉了,全部交给UE4里的FString类型和TEXT()来处理了。
运算符重载时的friend关键字
当我们在类(class)的定义外使用操作符(operator)的时候,操作符两边的参数都可以进行类型的隐式转换(implicit type conversions)。但是在类内定义操作符的时候,只有右手边的参数可以执行类型的隐式转换。
比如说我们声明一个这样的类:1
2
3
4
5
6class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
};
这种方式对运算符的重载,允许我们这样操作:1
2
3
4
5Message message("Test");
std::string msg("Test");
if (message == msg) { // Message类可以和std::string类型的字符串比较
// do stuff...
}
但是当我们把比较顺序换一下:1
if (msg == message) { // this won't compile
就会编译出错,原因很明显,在类内定义操作符的时候只有右手边的参数可以执行隐式转换,上面明显没有匹配的类型。
解决方案就是增加一个匹配类型:1
2
3
4
5
6
7class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
friend bool operator==(const std::string& lhs, const Message& rhs);
};
或者声明一个隐式转换操作符转到我们想要的类型(嘛这里不是很熟悉,我也没完全明白):1
2
3
4
5
6
7class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
operator std::string() const;
};
除此之外,还有一个需要注意的是,当我们重载操作符需要参照到类的私有成员的时候也必须使用friend限定。
至于操作符重载最好是以内联函数的形式这种结论我没有依据,还是要注意一些为好。
参考资料