参考代码仓库:https://github.com/jimboyeah/demo/blob/cppDemos/src/operators.cpp
operators 运算符重载
C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的参数列表必须不同,但不能仅通过返回类型的差别来重载函数
。
操作符重载方式有三种,类成员函数、友元函数、全局函数。使用类成员函数实现操作符重载,其函数列表中隐含了第二参数为 this 指针,不在参数列表中编写出来。如果使用码友元函数或全局函数,则需要在参数列表中增加这个隐含的参数,增加的这个参数可以用来代替 this 指针。
运算符重载 5 种基本类型:
- overloaded operator;
- user-defined conversion function;
- allocation function;
- deallocation function;
- user-defined literal.
罗列如下:
operator op
operator type
operator new
operator new []
operator delete
operator delete []
operator "" suffix-identifier (since C++11)
其中 op
可以以下 38 个操作符号之一:
+ - * / % ˆ & | ~ ! = < > += -= *= /= %= ˆ= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> ( ) [ ]
其中 operator
是运算符重载关键字,事实上可以将运算符重载当作函数来看待,即每个重载的运算就是一个对应的函数。
此表中,@ 是所有匹配运算符的占位符号:
- 前缀运算符即是 @a;
- 后缀运算符即是 a@,除
->
外; - 中间点位的运算符即是 a@b,除
=
外;
除内置运算符,built-in operators,重载运算符都可以用函数式调用:
std::string str = "Hello, ";
str.operator+=("world"); // same as str += "world";
operator<<(operator<<(std::cout, str) , '\n'); // same as std::cout << str << '\n';
// (since C++17) except for sequencing
在 C++ 中,标准库本身对左移运算符 << 和右移运算符 >> 进行了重载,使其能够用于不同数据的输入输出,但是输入输出的对象只能是 C++ 内置的数据类型,例如 bool、int、double 和标准库所包含的类类型,例如 string、complex、ofstream、ifstream 等。
习惯上,输入输出运算符号是 cin >> 和 cout << 这样使用的,实现自己的输入输出运算符的重载,通常使用友元函数的方式来实现,如果使用成员函数来重载会出现 obj << cout;
这种不自然的代码。
示范实现 <<、>>、[] 以及 () 强制类型转换运算符重载:
#include <string>
#include <cstdarg>
#include <iostream>
using namespace std;
/*-------------------------------*/
// Header
/*-------------------------------*/
class Base
{
public:
const char * text = "Test content...";
Base(const char *);
void operator=(Base &b);
const char & operator[](int) const;
friend ostream & operator<<(basic_ostream<char> &out, Base & b);
ostream & operator<<(basic_ostream<char> &out);
operator const char *(); // 重载强制类型转换运算符
};
/*-------------------------------*/
// Implementation
/*-------------------------------*/
Base::Base(const char * value)
{
this->text = value;
}
void Base::operator=(Base &b)
{
this->text = b.text;
}
Base::operator const char *()
{
return this->text;
}
const char & Base::operator[](int index) const
{
return this->text[index];
}
// The problem is that you define it inside the class, which
// a) means the second argument is implicit (this) and
// b) it will not do what you want it do, namely extend std::ostream.
ostream & Base::operator<<(basic_ostream<char> &out)
{
return out << "Base.text = " << this->text;
}
ostream & operator<<(basic_ostream<char> &out, Base & b)
{
return out << "Base.text = " << b.text;
}
int main(int argc, char *argv[])
{
Base a{"Some text..."};
Base b{"More text..."};
b = a;
std::cout << "after operator<< : " << a << std::endl;
std::cout << "after operator = : " << b << std::endl;
std::cout << "after operator[1]: " << b[1] << std::endl;
a << std::cout << " <--- use operator << as member function" << endl;
std::cout << "after typecast: " << (const char *)b << endl;
std::cout << "another typecast: " << b.operator const char *() << endl;
}
另外,注意一下 operator<< 如果以成员函数的方式实现,这样做的话,表示需要通过成员函数调用的方式来使用输出操作符,也就是要在 << 的左侧写类实例。
展示了强制类型转换运算符的两种方式,一种是以 C 风格的类型转换,另一种是成员函数方式的类型转换,语法看起来真的很怪诞!
网友评论