zoukankan      html  css  js  c++  java
  • C++解析(21):四个操作符

    0.目录

    1.逻辑操作符的陷阱

    2.逗号操作符的分析

    3.前置操作符和后置操作符

    4.小结

    1.逻辑操作符的陷阱

    逻辑运算符的原生语义:
    操作数只有两种值(truefalse
    逻辑表达式不用完全计算就能确定最终值
    最终结果只能是true或者false

    示例——短路法则:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int func(int i)
    {
        cout << "int func(int i) : i = " << i << endl;
        
        return i;
    }
    
    int main()
    {
        if( func(0) && func(1) )
        {
            cout << "Result is true!" << endl;
        }
        else
        {
            cout << "Result is false!" << endl;
        }
        
        cout << endl;
        
        if( func(0) || func(1) )
        {
            cout << "Result is true!" << endl;
        }
        else
        {
            cout << "Result is false!" << endl;
        }
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    int func(int i) : i = 0
    Result is false!
    
    int func(int i) : i = 0
    int func(int i) : i = 1
    Result is true!
    

    逻辑操作符可以重载吗?重载逻辑操作符有什么意义

    示例——重载逻辑操作符:

    #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);
        
        if( func(t0) && func(t1) )
        {
            cout << "Result is true!" << endl;
        }
        else
        {
            cout << "Result is false!" << endl;
        }
        
        cout << endl;
        
        if( func(1) || func(0) )
        {
            cout << "Result is true!" << endl;
        }
        else
        {
            cout << "Result is false!" << endl;
        }
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    Test func(Test i) : i.value() = 1
    Test func(Test i) : i.value() = 0
    Result is false!
    
    Test func(Test i) : i.value() = 0
    Test func(Test i) : i.value() = 1
    Result is true!
    

    问题的本质分析

    1. C++通过函数调用扩展操作符的功能
    2. 进入函数体前必须完成所有参数的计算
    3. 函数参数的计算次序是不定的
    4. 短路法则完全失效

    逻辑操作符重载后无法完全实现原生的语义!

    一些有用的建议:

    • 实际工程开发中避免重载逻辑操作符
    • 通过重载比较操作符代替逻辑操作符重载
    • 直接使用成员函数代替逻辑操作符重载
    • 使用全局函数对逻辑操作符进行重载

    2.逗号操作符的分析

    逗号操符( , )可以构成逗号表达式:

    • 逗号表达式用于将多个子表达式连接为一个表达式
    • 逗号表达式的值为最后一个子表达式的值
    • 逗号表达式中的前N-1个子表达式可以没有返回值
    • 逗号表达式按照从左向右的顺序计算每个子表达式的值

    示例——逗号表达式之坑:

    #include <iostream>
    
    using namespace std;
    
    void func(int i)
    {
        cout << "func() : i = " << i << endl;
    }
    
    int main()
    {   
        int a[3][3] = {
            (0, 1, 2),
            (3, 4, 5),
            (6, 7, 8)
        };
        
        int i = 0;
        int j = 0;
        
        while( i < 5 )    
            func(i),
        
        i++;
            
        for(i=0; i<3; i++)
        {
            for(j=0; j<3; j++)
            {
                cout << a[i][j] << '	';
            }
            cout << endl;
        }
        
        (i, j) = 6;
        
        cout << "i = " << i << endl;
        cout << "j = " << j << endl;
    
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    func() : i = 0
    func() : i = 1
    func() : i = 2
    func() : i = 3
    func() : i = 4
    2	5	8	
    0	0	0	
    0	0	0	
    i = 3
    j = 6
    

    重载逗号操作符:

    • C++重载逗号操作符合法的
    • 使用全局函数对逗号操作符进行重载
    • 重载函数的参数必须有一个是类类型
    • 重载函数的返回值类型必须是引用

    示例——重载逗号操作符:

    #include <iostream>
    
    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);
        Test tt = (func(t0), func(t1)); // Test tt = func(t1);
        
        cout << tt.value() << endl; // 1
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    func() : i = 1
    func() : i = 0
    1
    

    虽然最终结果是正确的,但是中间过程出错了!

    问题的本质分析

    1. C++通过函数调用扩展操作符的功能
    2. 进入函数体前必须完成所有参数的计算
    3. 函数参数的计算次序是不定的
    4. 重载后无法严格从左向右计算表达式

    示例——不重载逗号操作符:

    #include <iostream>
    
    using namespace std;
    
    class Test
    {
        int mValue;
    public:
        Test(int i)
        {
            mValue = i;
        }
        int value()
        {
            return mValue;
        }
    };
    
    Test func(Test& i)
    {
        cout << "func() : i = " << i.value() << endl;
        
        return i;
    }
    
    int main()
    {   
        Test t0(0);
        Test t1(1);
        Test tt = (func(t0), func(t1)); // Test tt = func(t1);
        
        cout << tt.value() << endl; // 1
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    func() : i = 0
    func() : i = 1
    1
    

    不重载逗号操作符反而是对的!!!

    工程中不要重载逗号操作符!

    3.前置操作符和后置操作符

    下面的代码有没有区别?为什么?

    下列代码中的i++;++i;在汇编代码中是一样的!

    int main()
    {
        int i = 0;
    
        i++;
    
        ++i;
    
        return 0;
    }
    

    意想不到的事实:

    • 现代编译器产品会对代码进行优化
    • 优化使得最终的二进制程序更加高效
    • 优化后的二进制程序丢失了C/C++的原生语义
    • 不可能从编译后的二进制程序还原C/C++程序

    C/C++开发的软件无法完全反编译!

    ++操作符可以重载吗?如何区分前置++和后置++

    ++操作符可以被重载:

    • 全局函数成员函数均可进行重载
    • 重载前置++操作符不需要额外的参数
    • 重载后置++操作符需要一个int类型的占位参数

    示例——重载++操作符:

    #include <iostream>
    
    using namespace std;
    
    class Test
    {
        int mValue;
    public:
        Test(int i)
        {
            mValue = i;
        }
        
        int value()
        {
            return mValue;
        }
        
        Test& operator ++ ()
        {
            ++mValue;
            
            return *this;
        }
        
        Test operator ++ (int)
        {
            Test ret(mValue);
            
            mValue++;
            
            return ret;
        }
    };
    
    int main()
    {
        Test t(0);
        cout << "t.value() = " << t.value() << endl;
        
        Test tt = t++;
        cout << "t.value() = " << t.value() << endl;
        cout << "tt.value() = " << tt.value() << endl;
        
        tt = ++t;
        cout << "t.value() = " << t.value() << endl;
        cout << "tt.value() = " << tt.value() << endl;
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    t.value() = 0
    t.value() = 1
    tt.value() = 0
    t.value() = 2
    tt.value() = 2
    

    真正的区别:

    • 对于基础类型的变量
      1. 前置++的效率与后置++的效率基本相同
      2. 根据项目组编码规范进行选择
    • 对于类类型的对象
      1. 前置++的效率高于后置++
      2. 尽量使用前置++操作符提供程序效率

    4.小结

    • C++从语法上支持逻辑操作符重载
    • 重载后的逻辑操作符不满足短路法则
    • 工程开发中不要重载逻辑操作符
    • 通过重载比较操作符替换逻辑操作符重载
    • 通过专用成员函数替换逻辑操作符重载
    • 逗号表达式从左向右顺序计算每个子表达式的值
    • 逗号表达式的值为最后一个子表达式的值
    • 操作符重载无法完全实现逗号操作符的原生意义
    • 工程开发中不要重载逗号操作符
    • 编译优化使得最终的可执行程序更加高效
    • 前置++操作符和后置++操作符都可以被重载
    • ++操作符的重载必须符合其原生语义
    • 对于基础类型,前置++与后置++的效率几乎相同
    • 对于类类型前置++的效率高于后置++
  • 相关阅读:
    Vue入门
    吃透SprinngBoot
    SSM整合详解
    Linux查找端口并关闭
    接入腾讯云的OCR识别身份证信息
    IDEA 快捷键《宋红康版》
    Mysql详解
    docker常见命令
    SpringBoot集成Redis
    使用mybatis出现异常
  • 原文地址:https://www.cnblogs.com/PyLearn/p/10087177.html
Copyright © 2011-2022 走看看