zoukankan      html  css  js  c++  java
  • 操作符重载(三)

    1. 结论

    前面两次笔记都是C++中可以重载且无副作用的操作符,本次笔记比较特殊,主要列出两个C++语法允许重载、但在工程中不应该(不允许)重载的操作符:

    • 逻辑操作符 &&||
    • 逗号操作符,构成的逗号表达式

    这两个操作符在工程中不允许重载的原因是:重载后无法完全实现操作符的原生语义。

    2. 逻辑操作符重载

    先来回忆一下逻辑操作符的原生语义

    • 操作数只有true和false两种值
    • 逻辑表达式不需要完全计算就能确定最终结果(短路法则)
    • 最终结果也只能是true或者false

    C++语法是允许重载逻辑操作符的,看下面的示例代码

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Test
    {
        int mValue;
    public:
        Test(int v)
        {
            mValue = v;
        }
        int value() const
        {
            return mValue;
        }
    };
    
    bool operator && (const Test &l, const Test &r)
    {
        return l.value() && r.value();
    }
    
    bool operator || (const Test &l, const Test &r)
    {
        return l.value() || r.value();
    }
    
    Test func(Test i)
    {
        cout << "Test func(Test i) : i.value() = " << i.value() << endl;
    
        return i;
    }
    
    int main()
    {
        Test t0(0);
        Test t1(1);
    
        /*
         * 根据短路法则,期望的正确输出为:
         * Test func(Test i) : i.value() = 0
         * Result is false!
        */
        if( func(t0) && func(t1) )
        {
            cout << "Result is true!" << endl;
        }
        else
        {
            cout << "Result is false!" << endl;
        }
    
        cout << endl;
    
        /*
         * 根据短路法则,期望的正确输出为:
         * Test func(Test i) : i.value() = 1
         * Result is true!
        */
        if( func(1) || func(0) )
        {
            cout << "Result is true!" << endl;
        }
        else
        {
            cout << "Result is false!" << endl;
        }
    
        return 0;
    }
    

    代码中注释了我们期待的正确输出,但实际运行结果一个都没对上,为什么呢?

    • 操作符重载的本质是通过函数调用扩展操作符的功能,47行和63行的if条件分别等价于operator && (func(t0), func(t1))operator || (func(t1), func(t0))
    • 重载函数在进入函数体之前必须完成所有参数的计算,而函数参数的计算顺序是不确定的
    • 短路法则完全失效,逻辑操作符重载后无法完全实现原生语义

    因此,在工程中应当避免重载逻辑操作符,建议采用重载比较操作符或提供成员函数的方式,来代替重载逻辑操作符。

    3. 逗号操作符重载

    逗号操作符,可以构成逗号表达式,下面是逗号表达式的原生语义

    • 逗号表达式用于将多个子表达式连接为一个表达式,如exp1, exp2, exp3, ... , expN
    • 逗号表达式中前N-1个子表达式可以没有返回值,最后一个子表达式必须有返回值
    • 逗号表达式的最终结果为最后一个子表达式的值
    • 逗号表达式严格按照从左向右的顺序计算每个子表达式的值
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    void func(int i)
    {
        cout << "func() : i = " << i << endl;
    }
    
    int main()
    {
        int a[3][3] =
        {
            (0, 1, 2),   //逗号表达式,等价于a[3][3] = {2, 5, 8,};
            (3, 4, 5),
            (6, 7, 8)
        };
    
        int i = 0;
        int j = 0;
    
        while (i < 5)
            func(i),    //逗号表达式,等价于func(i), i++;
    
                 i++;
    
        cout << endl;
    
        for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 3; j++)
            {
                cout << a[i][j] << endl;
            }
        }
    
        cout << endl;
    
        (i, j) = 6;  //逗号表达式,等价于 j = 6;
    
        cout << "i = " << i << endl;
        cout << "j = " << j << endl;
    
        return 0;
    }
    

    在C++中重载逗号操作符是合法的,重载函数的参数必须有一个是类类型,且重载函数的返回值类型必须是引用

    Class &operator , (const Class &a, const Class &b)
    {
        return const_cast<Class &>(b);
    }
    

    看下面的示例代码

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Test
    {
        int mValue;
    public:
        Test(int i)
        {
            mValue = i;
        }
        int value()
        {
            return mValue;
        }
    };
    
    Test &operator , (const Test &a, const Test &b)
    {
        return const_cast<Test &>(b);
    }
    
    Test func(Test &i)
    {
        cout << "func() : i = " << i.value() << endl;
    
        return i;
    }
    
    int main()
    {
        Test t0(0);
        Test t1(1);
    
        /*
         * 期望的正确输出为:
         * func() : i = 0
         * func() : i = 1
         * 1
        */
        Test tt = (func(t0), func(t1));
        cout << tt.value() << endl;
    
        return 0;
    }
    

    虽然第44行输出结果和预期相符,但第43行输出和预期不符,原因和逻辑操作符重载一样,都是由函数参数计算顺序的不确定性造成的,也就是说:

    • 逗号操作符重载后,构成的逗号表达式无法严格按照从左向右的顺序计算各个子表达式
    • 逗号操作符重载后无法完全实现原生语义
    • 因此,在工程中不要重载逗号操作符
  • 相关阅读:
    C语言的setlocale和localtime函数(C++也可用)
    stdlib.h,string.h,wchar.h的函数列表(cplusplus.com就有,很清楚)goodx
    DataSet与JSON互转
    21 步助你成为成功的 Web 开发者(激情不是被动的:它是一种对行动起来的追求)
    开发人员与非技术同事沟通的七个聪明策略
    页面架构
    可视化配置以及Net应用MemCache在win7
    NPOI以及在ASP.NET MVC中的使用
    TCP/IP协议
    springMVC+angular+bootstrap+mysql的简易购物网站搭建
  • 原文地址:https://www.cnblogs.com/songhe364826110/p/11581043.html
Copyright © 2011-2022 走看看