C++ Operators 操作符重载

C++ Operators

参考代码仓库:https://github.com/jimboyeah/demo/blob/cppDemos/src/operators.cpp

operators 运算符重载

  • https://www.runoob.com/cplusplus/input-output-operators-overloading.html

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).operator@( ) operator@(a) !cin 等价 cin.operator!()
a@b (a).operator@(b) operator@(a, b) cout << 42 等价 cout.operator<<(42)
a=b (a).operator=(b) 不可用 string s; s = "abc"; 等价 s.operator=("abc")
a(b...) (a).operator()(b...) 不可用 random_device r; auto n = r(); 等价 r.operator()()
a[b] (a).operator 不可用 map m; m[1] = 2; 等价 m.operator
a-> (a).operator->( ) 不可用 auto p = make_unique(); p->bar() 等价 p.operator->()
a@ (a).operator@(0) operator@(a, 0) vector::iterator i = v.begin(); i++ 等价 i.operator++(0)

此表中,@ 是所有匹配运算符的占位符号:

  • 前缀运算符即是 @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 
#include 
#include 

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 &out, Base & b);
    ostream & operator<<(basic_ostream &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 &out)
{
    return out << "Base.text = " << this->text;
}


ostream & operator<<(basic_ostream &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 风格的类型转换,另一种是成员函数方式的类型转换,语法看起来真的很怪诞!

你可能感兴趣的:(C++ Operators 操作符重载)