28 逻辑操作符的陷阱

1 逻辑运算符规则

  • 逻辑运算符(&&||!)的原生语义

    • 操作数只有两种值(truefalse
    • 逻辑表达式不用完全计算就能确定最终值
    • 最终结果只能是 true 或者 false
  • 示例1:逻辑表达式

    • Demo

      #include <iostream>
      #include <string>
      
      using namespace std;
      
      int func(int i)
      {
          cout << "int func(int i) : i = " << i << endl;
          
          return i;
      }
      
      int main()
      {
          if( 0 && 1 ) {
              cout << "Result is true!" << endl;
          }
          else {
              cout << "Result is false!" << endl;
          }
          cout << endl;
          
          if( 0 || 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;
          }
          cout << endl;
          
          if( func(0) || func(1) ) {
              cout << "Result is true!" << endl;
          }
          else {
              cout << "Result is false!" << endl;
          }
          
          return 0;
      }
      
    • 编译运行

      Result is false!
      
      Result is true!
      
      int func(int i) : i = 0
      Result is false!
      
      int func(int i) : i = 0
      int func(int i) : i = 1
      Result is true!
      

2 重载逻辑表达式

  • 【问题】逻辑操作符可以重载么?重载逻辑操作符有什么意义?

    • 不可以,会引入陷阱,违背了逻辑操作符的原生语义
  • 示例2:重载逻辑操作符

    • Demo

      #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) )  // <=>函数调用形式: if(operator && (func(to),func(t1)))
          {
              cout << "Result is true!" << endl;
          }
          else
          {
              cout << "Result is false!" << endl;
          }
          
          cout << endl;
          
          if( func(1) || func(0) )  // <=>函数调用形式: if(operator || (func(to),func(t1)))
          {
              cout << "Result is true!" << endl;
          }
          else
          {
              cout << "Result is false!" << endl;
          }
          
          return 0;
      }
      
    • 编译运行

      Test func(Test t) : t.value = 1
      Test func(Test t) : t.value = 0
      Result is false!
      Test func(Test t) : t.value = 1
      Test func(Test t) : t.value = 0
      Result is true!
      
    • 问题:短路法则失效,且调用顺序不定

  • 问题的本质分析

    • C++ 通过函数调用扩展操作符的功能
    • 进入函数体前必须完成所有参数的计算
    • 函数参数的计算次序是不定的
    • 短路法则完全失效
  • 逻辑操作符重载后无法完全实现原生语义

  • Tips

    • 实际工程开发中避免重载逻辑操作符
    • 通过重载比较操作符(与 truefalse 比较)代替逻辑操作符重载
    • 直接使用成员函数代替逻辑操作符重载
    • 使用全局函数对逻辑操作符进行重载
posted @ 2020-10-30 19:31  nxgy  阅读(64)  评论(0编辑  收藏  举报