zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    curl post
    mysql存储引擎
    梳理版本控制器:SVN和Git比较
    详细说明php的4中开源框架(TP,CI,Laravel,Yii)
    五种常见的 PHP 设计模式
    php+ajax实现跨域单点登录
    laravel
    Gitlab配置webhooks实现自动化部署
    linux CentOs7 安装gitlab
    身份证验证
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/6900988.html
Copyright © 2011-2022 走看看