1. 程式人生 > >邏輯操作符的陷阱(三十二)

邏輯操作符的陷阱(三十二)

C++ 重載邏輯操作符 邏輯操作符陷阱 比較操作符

我們今天來看看邏輯操作符,它的原生語義是:操作數只有兩種值(true 和 false),邏輯表達式不用完全計算就能確定最終值,其最終結果只能是 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;
}

我們利用在 C 語言中所學的知識,輕易可知第一個輸出 false,第二個輸出 true。並且第一個只打印出 func(0),第二個兩個都會打印出。我們來看看編譯結果

技術分享圖片

結果是這樣的,那麽這塊是否沒有什麽可講的嗎?邏輯操作符可以重載嗎?重載邏輯 操作符有什麽意義?我們看個示例代碼

#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& r, const Test& l)
{
    return r.value() && l.value();
}

bool operator || (const Test& r, const Test& l)
{
    return r.value() || l.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;
}

我們看到重載了邏輯操作符,在 func 函數中傳入的是 Test 對象,然後看看編譯結果是否和之前的一樣呢?

技術分享圖片

我們看到雖然最後的結果是一樣的,但是調用 func 函數和之前不同了。兩次兩個都調用了,這是怎麽回事呢?我們回到操作符重載的本質來看,它是函數重載,我們試著寫下它的原型,如下

#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& r, const Test& l)
{
    return r.value() && l.value();
}

bool operator || (const Test& r, const Test& l)
{
    return r.value() || l.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( operator && (func(t0), func(t1)) )
    {
        cout << "Result is true!" << endl;
    }
    else
    {
        cout << "Result is false!" << endl;
    }
    
    cout << endl;
    
    if( operator || (func(1), func(0)) )
    {
        cout << "Result is true!" << endl;
    }
    else
    {
        cout << "Result is false!" << endl;
    }
    
    return 0;
}

我們看到在第 43 和 54 行寫成這樣的形式,再次編譯看看

技術分享圖片

結果和之前的是一樣的,這便證明了操作符重載的本質是函數重載。C++ 通過函數調用擴展操作符的功能,進入函數體前必須完成所有參數的計算。函數參數的計算次序是不定的,短路法則則完全失效。因此,邏輯操作符重載後無法完全實現原生的語義

我們通常在實際工程開發中避免重載邏輯操作符,通過重載比較操作符代替邏輯操作符重載。直接使用成員函數代替邏輯操作符重載,使用全居函數對邏輯操作符進行重載。通過對邏輯操作符重載的學習,總結如下:1、C++ 從語法上支持邏輯操作符重載,重載後的邏輯不滿足短路法則。2、工程開發中不要重載邏輯操作符;3、通過重載比較操作符替換邏輯操作符重載;4、通過專用成員函數替換邏輯操作符重載


歡迎大家一起來學習 C++ 語言,可以加我QQ:243343083

邏輯操作符的陷阱(三十二)