zoukankan      html  css  js  c++  java
  • C/C++基础----重载运算与类型转换

    • 非成员版本

      data1 + data2;
      operator+(data1, data2);

    • 成员版本

      data1 += data2;
      data1.operator+=(data2);

    • 不建议的重载

    逻辑与、逻辑或、逗号的运算对象求值顺序规则无法保留。
    &&和||的重载版本也没法保留内置运算符的短路求值属性,两个运算对象总是会被求值。
    逗号和取址,已经在C++中定义了其用于类对象是的特殊含义,已经有了内置的含义,一般不应该重载。
    
    • 有些运算符必须作为成员,有些则作为普通函数更好

      1. 赋值= 下标[] 调用() 成员访问箭头->必须是成员
      2. 复合赋值一般应该是成员,但并非必须
      3. 改变对象状态的运算符或者与给定类型密切相关的运算符,如++,--,解引用通常是成员
      4. 具有对称性的,可能转换任意一端的运算符对象,如算术、相等性、关系和位运算,通常是非成员。
    • 输出运算符<<

    ostream &operator<<(ostream &os, const Sales_data &item)
    输出运算符不太考虑格式化操作,使用户有权控制输出细节
    与iostream标准库兼容的输入输出运算符必须是非成员函数
    
    • 输入运算符>>
    istream &operator>>(istream &is, Sales_data &item)
    输入运算符必须处理可能失败的情况(数据类型错误,到底文件尾或遇到输入流其他错误)
    
    • 算术和关系
    通常定义为非成员,通常不需要改变运算对象(常量引用),计算得到一个新值。
    如定义了复合赋值,最有效的是使用复合赋值来定义算术运算。
    Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
    
    bool operator==(const Sales_data &lhs, cosnt Sales_data &rhs)
    bool operator!=(const Sales_data &lhs, cosnt Sales_data &rhs)
    
    • 关系运算符
    1 定义顺序关系,与关联容器对关键字的要求一致(唯一性、传递性、等价性)
    2 如果同时含有==的话,则定义一种关系令其与==保持一致
    当存在一种唯一可靠的<定义,且和==产生的结果一致时,才定义<
    
    • 赋值运算符
    StrVec &StrVec::operator=(initializer_list<string> il)
    Sales_data &Sales_data::operater+=(const Sales_data &rhs)
    赋值运算符必须是成员函数,复合赋值也通常定义为成员函数。
    一般算术运算调用复合赋值,可读写较好
    
    • 下标运算
    通常返回引用,最好同时定义常量和非常量版本,必须成员函数
    std::string &operator[](std::size_t n) {return elements[n];}
    const std::string &operator[](std::size_t n) const {return elements[n];}
    
    • 递增递减
    StrBlobPtr& StrBlobPtr::operator++()    前置版本
    StrBlobPtr StrBlobPtr::operator++(int)	  后置版本
    后置可以调用前置来完成,前置版本需检查递增操作的有效性。一般设定为成员函数。
    
    • 成员访问
    class StrBlob{
    public:
    std::string &operator*() const
    {	auto p = check(curr, “dereference past end”;
    	return (*p)[curr];
    }
    std::string *operator->() const
    {
    	return & this->operator*();
    }
    }
    
    箭头必须成员,解引用也通常成员
    箭头运算符永远不能丢掉成员访问的基本含义
    point->mem
    point必须是指向类对象的指针或者是重载了operator->的类对象
    1是指针,等价于(*point).mem
    2是对象,调用point.operator->()的结果来获取mem。如果返回的是指针则执行第1步;如果返回的结果本身重载了->,则重复调用。或者返回错误。
    
    • 调用运算符
    函数对象,同时也能储存状态,比普通函数更灵活
    同一个对象里可以重载好几个不同版本的调用函数,同时可以改变数据成员来定制不同操作。隐含的this参数呢???看调用的形式
    
    • lambda是未命名类的未命名对象
    默认情况下,是一个const成员函数,不能改变它捕获的变量。显式声明为mutable则不是。
    产生的类不含默认构造函数、赋值运算符及默认析构函数??
    是否含有默认的拷贝/移动构造要视捕获的数据类型而定。
    
    • 标准库定义的函数对象
    算术 关系 逻辑
    plus equal_to logical_and
    minus not_equal_to logical_or
    multiplies greater logical_not
    divides greater_equal
    modulus less
    negate less_equal
    常用来替换算法中的默认运算符,这些函数对象对指针同样适用。
    sort(a.beg,a.end, less<string*>() );  //正确
    而用<,则将产生未定义的行为
    
    关联容器使用less<key_type>对元素排序,可以定义一个指针作为关键字的set或map而无须直接声明less
    
    • 可调用对象
    函数、函数指针、lambda表达式、bind创建的对象、重载了函数调用运算符的类。
    fun &fun和funP打印的地址是一样的。funP可以被赋值,而fun不可以。有两种解释
    1函数名与FunP函数指针都是函数指针。fun是一个函数指针常量,funP是一个函数数指针变量。
    2函数名和数组名实际上都不是指针,但是,在使用时可以退化成指针,即编译器可以帮助我们实现自动的转换。
    
    既然都是都有指针的效果,为什么要定义函数指针?
    二义性问题,如有几个版本add函数,不知道哪个?
    起到一定的封装效果,可以提供统一接口。C++虚函数表就是通过函数指针实现。
    
    不同类型调用对象可能共享同一种调用形式
    map<string, int(*)(int, int)> binops;能存函数指针,存不了函数对象和lambda
    
    function类 <functional>
    可以接受同调用类型的可调用对象
    function<int (int, int)> f1=add;
    
    map<string,function<int(int,int)>> binops = {
    	{“+”, add},
    	{“-”, std::minus<int>()} };
    binops[“+”](10, 5);   //调用add(10, 5)
    
    类型转换可以面向任何可以作为返回类型的类型,不允许转换成数据或函数类型。,必须定位为成员函数,通常const。
    编译器只能进行一个用户定义的类型转换,但是隐式地用户定义类型转换可以置于一个标准(内置)类型转换之前或之后。
    explicit operator int() const {return val;}
    static_cast<int>(si)+3;
    一个例外,当用作条件时,编译器会将显式的类型转换自动应用于它。
    if while do  for  与或非 ?:
    
    • 避免二义性
    两个类提供相同的类型转换
    类定义了多个转换规则
    当使用用户定义的类型转换时,如果包含标准类型转换,转换的级别决定了最佳匹配选择
    
  • 相关阅读:
    @RequestParam和@PathVariable用法小结
    Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法
    allator 对springBoot进行加密
    commons-lang3相关类实例
    JSP自定义标签
    Netty的简单Demo
    Spring-AOP为类增加新的功能
    深入理解abstract class和interface
    linux的基本操作
    GitHub从小白到熟悉<二>
  • 原文地址:https://www.cnblogs.com/logchen/p/10188158.html
Copyright © 2011-2022 走看看