chapter-14

// chapter-14.cpp : 重载运算符和类型转换(operator int()()const)
//

#include "stdafx.h"
#include<iostream>
#include<string>
#include<map>
#include<set>
#include<functional>
#include<algorithm>
#include<numeric>

using namespace std;

class Example_operator
{
public:
    Example_operator() = default;
    Example_operator(const string &s, const map<string, set<string>> &m) :id(s), information(m) {}
    friend ostream& operator<<(ostream &os,const Example_operator &rhs);
    friend istream& operator>>(istream &in, Example_operator &rhs);
    Example_operator operator+=(const Example_operator &rhs);
    friend Example_operator operator+(const Example_operator &lhs, const Example_operator &rhs);
    friend bool operator==(const Example_operator &lhs, const Example_operator &rhs);
    friend bool operator!=(const Example_operator &lhs, const Example_operator &rhs);

private:
    string id;
    map<string, set<string>> information;
    //void read_from_input();
};
//输入输出运算符,必须是非成员函数。const引用,不改变内容节省时间!
ostream& operator<<(ostream &os, const Example_operator &rhs)
{
    os << rhs.id <<":"<< endl;
    for (auto &r : rhs.information)
    {
        cout << "\b" << r.first << " : ";
        for (auto &&rs : r.second)
        {
            cout << rs << " ";
        }
        cout << endl;
    }
    return os;
}
istream& operator>>(istream &in, Example_operator &rhs)
{
    cout << "Please input the name:" << endl;
    in >> rhs.id;
    cout << "Please input something(keys value ...(; to stop!)),or q to quit..." << endl;
    if (in)                         //检查输入是否成功!输入运算符必须检查输入失败,而输出则不需要!
    //当出现输入错误是,最好是自己使用IO标准库来表示这些错误!
    {
        string key, value;
        while (cin >> key)
        {
            if (key == "q")
                break;
            else
            {
                set<string> tmp_set;
                while (cin >> value)
                {
                    if (value == ";")
                        break;
                    tmp_set.insert(value);
                }
                rhs.information[key] = tmp_set;
            }
        }
    }
    return in;
}

Example_operator Example_operator::operator+=(const Example_operator &rhs)
{
    Example_operator &sum = *this;
    if (sum.id == rhs.id)
    {
        for (auto &r : sum.information)
        {
            for (auto &k : rhs.information)
            {
                if (r.first == k.first)
                {
                    r.second.insert(k.second.cbegin(), k.second.cend());
                }
                else
                {
                    sum.information.insert(k);
                }
            }
        }
    }
    return sum;
}
Example_operator operator+(const Example_operator &lhs, const Example_operator &rhs)
{
    Example_operator sum = lhs;
    if (sum.id == rhs.id)
    {
        sum += rhs;
    }
    return sum;
}

bool operator==(const Example_operator &lhs, const Example_operator &rhs)
{
    return (lhs.id == rhs.id && lhs.information == rhs.information);
}

bool operator!=(const Example_operator &lhs, const Example_operator &rhs)
{
    return !(lhs == rhs);
}

class PrintString               //如果类定义了函数调用运算符,就可以像函数一样使用该对象!
{
public:
    PrintString(ostream &o = cout, char c = ' ') :os(o), sep(c) {}
    void operator()(const string &s) const { os << s << sep; }

private:
    ostream &os;
    char sep;
};


class SmallInt//构造函数将算术类型的值转换成smallInt对象,而类型转换运算符将smallInt对象转换成int!
{
public:
    SmallInt(int i = 0) :val(i)
    {
        if (i < 0 || i>255)
            throw out_of_range("Bad smallint value!");
    }
    operator int()const { return val; }//类型转换!(包含数组指针和函数指针)
private:
    size_t val;
};

class SmallInt_Explicit//显示类型转换,必须使用static_cast<int>强制转换!若为条件,则同样允许自动转换!
{
public:
    SmallInt_Explicit(int i = 0) :val(i)
    {
        if (i < 0 || i>255)
            throw out_of_range("Bad smallint value!");
    }
    explicit operator int()const { return val; }//定义类型转换!

private:
    size_t val;
};

int main()
{
    Example_operator stu01("xiaoming", { { "grade",{ "99" } },{ "car",{ "baoma" } } });
    cout << stu01 << endl;

    Example_operator stu02;
    cin >> stu02;
    cout << stu02 << endl;

    cout << (stu01 + stu02) << endl;

    PrintString printer;
    printer("abc");         //for_each(v.begin(),v.end(),printer(cout,'\n'))!;lambda是函数对象,编译器编译成一个未命名类的未命名对象!如果含有值捕获,则对应类将建有对应的数据成员!

    //标准库自带函数对象,定义在头文件functional中。主要应用于泛型算法中!
    //算术:plus<Type> minus   multiplies  divides modulus negate
    //关系:equal_to   not_equal_to    greater greater_equal   less    less_equal
    //逻辑:logical_and    logical_or  logical_ not
//plus<int> intadd;int sum=intadd(3,4)

    //函数、函数指针、lambda表达式、bind创建对象、重载运算符,均为可调用对象!可调用对象也有类型,为调用形式!int(int,int),接受2个int,返回一个int!
    //使用function储存可调用对象,定义在头文件functional中!
    //function<T> f;                f是一个储存可调用对象!
    //function<T> f(nullptr)
    //function<T> f(obj)
    //f                             将f作为条件,当f含有一个可调用对象为真!
    //f(args)                       调用f中的对象,参数为args
    //result_type                   返回可调用对象返回的类型
    //argument_type                 返回实参类型!
    //first_argument_type
    //second_argument_type
    //  function<int(int, int)> f1 = add;       函数指针
    //  function<int(int, int)> f2 = divide();  函数对象
    function<int(int, int)> f3 = [](int i, int j) {return i*j; };
    //map<string,function<int(int,int)>> binops={{"+",add}};
    //传入重载函数时,为了避免二义性,1、int (*fp)(int,int)=add;2、lambad

    //自定义类型转换,返回类型必须能作为函数的返回类型!(数组和函数不能返回,但其指针可以)
    SmallInt si;
    si = 4;                     //转为size_t
    cout << si + 3 << endl;     //size_t转为int,再执行整数的加法!
    //实际中很少定义类型转换符,但是定义向bool的类型转换还是比较普遍的现象!
    //为避免隐式类型转换引发错误结果,进行显示的类型转换运算符定义!
    SmallInt_Explicit sie = 3;
    cout << static_cast<int>(sie) + 4 << endl;      //当表达式被用作条件,显示类型转换会被隐式的执行!
    //避免二义性类型转换:1、f(b)=A(b)和b.operator(A),避免同时定义相同的类型转换!(构造函数和成员函数、同类避免即转int,又转double)2、除了转换为bool,应该避免定义类型转换!

    return 0;
}
//为自定义类对象定义重载运算符,有利于编写和阅读!(内置类型无法重载!)
//除了operator()外,其他重载运算符不能有默认实参!???
//不能重载的运算符《::   .*  . ?:》/可以重载的运算符《+    -   *   /(算术)   &(比较)   <<(IO)  [](下标)  ()(函数调用运算符 int operator()(int val) const{returnval<0?-val:val}) ->  &&(逻辑)  new》
//重载运算符应该与内置类型一致,有operator==则应该有operator!=,有operator<则应该有其他比较关系,逻辑和关系返回布尔值,算术返回类类型,赋值返回左侧对象的引用!
//具有对称性的运算符应该定义为非成员函数!如算术、相等、关系和位运算符!;复合赋值运算符应该是成员函数!

推荐阅读更多精彩内容