• C++运算符重载的妙用


    运算符重载(Operator overloading)是C++重要特性之中的一个,本文通过列举标准库中的运算符重载实例,展示运算符重载在C++里的妙用。详细包含重载operator<<,operator>>支持cin,cout输入输出。重载operator[],实现下标运算。重载operator+=实现元素追加;重载operator()实现函数调用。假设你对C++的运算符重载掌握的游刃有余。那就无需继续往下看了。

    运算符重载带来的优点就是——让代码变得简洁。以下将展示几个标准库因使用运算符重载而是代码简洁的实例。


    Hello, World与operator<<

    刚学C++时看到的第一个C++程序就是Hello World,它当时长得这样:

    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
    	cout << "Hello, world!" << endl;
    	return 0;
    }

    当时。我以为 cout << sth 和 cin >> xxx 这是“必须的格式”。

    而其实,这仅仅是运算符重载在标准库里的一个缩影而已。这里实际调用的是<string>定义的:

      extern template ostream& operator<<(ostream&, const char*);


    容器与operator[]

    以下展示vector和map因提供了operator[]而使程序变得简洁的实例。


    vector::operator[]

    STL 容器(Container)中的vector,map,都提供了operator[],对于vector,operator[]使得它的使用方法“和数组类似”,就是能够用下标訪问vector的元素:

    	int firstInt = ivec[0]; // operator[]
    	ivec[0] = 1; // 
    

    假设没有运算符重载。相同的功能非常可能就要写成:

    	int firstInt = ivec.get(0); 
    	ivec.set(0, 1); 
    

    这就不再像数组那么“亲切”了。

    以下的代码是求vector<int> ivec内全部元素和的代码:

    	int sum = 0;
    	for(int i=0; i < ivec.size(); i++) {
    		sum += ivec[i];
    	}


    map::operator[]

    类似的,operator[]使map很好用。比方使用标准库map和string的单词统计的核心代码仅仅有例如以下几行:
    	string word;
    	map<string, int> dict;
    	
    	while(cin >> word)
    	{
    		dict[word]++; // operator[]
    	}

    对于map,假设没有operator[],那上面的 dict[word]++ 一行要写成:

    map<string, int>::iterator it = dict.find(word);
    if(it != dict.end()) {
    	it->second++;
    }
    else {
    	dict.insert(make_pair(word, 1));
    }

    能够从cplusplus.com能够上看到,map的operator[]相当于:

    (*((this->insert(make_pair(x,T()))).first)).second
    这样的写法看起来非常难理解,能这么写是由于map::insert是有返回值的:

    pair<iterator,bool> insert ( const value_type& x );

    使用C++标准库实现的"单词统计",整个程序例如以下:

    #include <cstdio>
    #include <iostream>
    #include <map>
    #include <string>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
    	string word;
    	map<string, int> dict;
    	
    	while(cin >> word)
    	{
    		dict[word]++;
    	}
    	
    	// output:
    	for(map<string, int>::iterator it = dict.begin(); it != dict.end(); ++it)
    	{
    		cout << it->first << "	" << it->second << "
    ";
    	}
    	return 0;
    }
    
    这段程序不仅完毕了“单词统计”,还依照单词的字典顺序进行输出,这些全依赖于标准库的运算符重载。

    迭代器与operator++

    上面“单词统计”的代码。已经使用设计到了iterator,正是“迭代器”。简单地说,迭代器就是有指针功能的class类型;而它的“指针”功能。正是经由运算符重载实现的。

    比方以下代码能够输出vecotr<int> ivec的所有元素:

    	for(vector<int>::iterator it = ivec.begin(); 
    		it != ivec.end(); // operator!=
    		it++) { // operator++
    			printf("%d
    ",
    				*it); // operator*
    		}

    这段短短的代码调用了iterator重载的三个operator。运算符重载使得这里for循环的写法和数组的迭代方式类似。

    C/C++的原始指针支持的运算有:

    1. 解引用(dereference)运算
    2. 取成员(member access)运算
    3. 自增(increment)、自减(decrement)运算
    4. 算数加减运算

    实现以上功能。相应的运算符重载成员函数分别为:

    1. operator*()
    2. operator->()
    3. operator++()、operator--()
    4. operator+(int)、operator-(int)

    iterator至少实现了1,2,3中的一个。

    所有重装就能全然模拟指针支持的语法。要实现和指针类似的功能还需实现对于的函数内容。

    除了iterator。智能指针(shared_ptr等)也重载了以上几个运算符,使得他们用起来和原始指针很相似(语法形式上);但它们的“自己主动引用计数”能力除了借助了运算符重载。很多其它的应当归功与C++的RAII惯使用方法,兴许我将专门写一篇关于RAII妙用的文章来解释shared_ptr是怎样实现“自己主动引用计数”的。


    关于迭代器,最为激进的莫过于:

    copy(istream_iterator<char>(cin), istream_iterator<char>(), ostream_iterator<char>(cout, "")); 


    string与operator+=

    标准库的string,提供了operator[],使得用户能够使用下标运算符訪问字符串中的字符。这和char array, char pointer无异。比如:

    str1[0] = str2[0];
    str2[0] = 'A';

    除此之外,string还提供了重载了的operator+=。能够向已有的string对象追加字符和字符串(包含char array,char pointer)。

    比如:

    str1 += '!';
    str1 += str2;
    str1 += "literal string";


    函数对象与operator()

    在<algorithm>提供的众多算法中,大多都有两个版本号。当中一个版本号多出一个叫做Function Object的參数,比方sort:

    template <class RandomAccessIterator>
      void sort ( RandomAccessIterator first, RandomAccessIterator last );
    
    template <class RandomAccessIterator, class Compare>
      void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
    comp就被称作是Function Object。

    究竟什么是Function Object呢?字面理解就是一个能够当函数调用的对象。事实上就是一个重载了operator()的对象,比方要实现对一个vector<string>依照字符串长度对元素排序。能够传入一个这个Functor的实例:

    struct StrLenComp
    {
    	bool operator()(const string& a, const string& b) {
    		return a.length() < b.length();
    	}
    };
    
    当然,假设你对C++11非常熟悉。这个Functor的Function Object全然能够用一行的lambda表达式表示:

    [](const string& a, const string& b){ return a.length() < b.length(); }


    小结

    上面列出的是标准库中最广为认知的运算符重载的样例。但标准库使用运算符重载的地方远不止此。


    实质

    C++中运算符重载实际上和函数重载、成员函数重载并没有两样。仅仅是写起来更简洁一点罢了。

    编译时,它们都会被改动为编译器内部的名称,也相同支持“重载”——參数列表不同。


    代码实例

    本文仅仅讲了运算符重载在C++中各种“奇妙”的使用方法。你是不是也摩拳擦掌,想要一展身手了?你是想要体验一把这些特性的“好用之处”。还是想要“自己动手”写几个运算符重载函数?预知怎样重载运算符。请移步:http://blog.csdn.net/xusiwei1236/article/details/39528813

  • 相关阅读:
    ECharts之柱状图 饼状图 折线图
    Vue自定义指令(directive)
    HDU 1231 最大连续子序列
    POJ 2533 Longest Ordered Subsequence
    HDU 1163 Eddy's digital Roots
    HDU 2317 Nasty Hacks
    HDU 2571 命运
    HDU 4224 Enumeration?
    HDU 1257 最少拦截系统
    HDU 2740 Root of the Problem
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/6900988.html
Copyright © 2020-2023  润新知