2014-03-29 133 views
0

我在下面的代碼中有衝突。返回一個對象的const引用

#include <iostream> 
using std::cout; 
using std::endl; 

class TestApp { 
public: 

    TestApp(int _x = 9) { 
     cout << "default constructor\n"; 
    } 

    TestApp(const TestApp &app) { 
     cout << "Copy constructor\n"; 
    } 

    ~TestApp() { 
     cout << "destructor\n"; 
    } 

    void setX(int _x) { 
    } 

    const TestApp &operator=(TestApp &obj) { 
     cout << "= operator\n"; 
     return *this; 
    } 

    void setX(int _x) { 
     cout << "Inside setX\n"; 
    } 
}; 

int main() { 
    TestApp app1; 
    TestApp app2; 
    TestApp app3; 
    (app1 = app2) = app3; // 1 
    app1 = app2 = app3; // 2 
    app1.setX(3) 
    return 0; 
} 

我得到這個錯誤:第1行main.cpp:38: error: passing ‘const TestApp’ as ‘this’ argument of ‘const TestApp& TestApp::operator=(TestApp&)’ discards qualifiers 但是我可以用app1.setX(3);

main.cpp:38: error: no match for ‘operator=’ in ‘app1 = app2.TestApp::operator=(((TestApp&)(& app3)))’ 
main.cpp:28: note: candidates are: const TestApp& TestApp::operator=(TestApp&) 

,並使其工作,我應該讓operator=像:

TestApp &operator=(const TestApp &obj) { 
     cout << "= operator\n"; 
     return *this; 
} // works for 1 

TestApp &operator=(TestApp &obj) { 
     cout << "= operator\n"; 
     return *this; 
} // works for 2 

爲什麼如果我刪除const關鍵字它的作品?並且行1 app1對象不是常量。

+0

而解決方案1不會爲第2行工作? – deviantfan

+0

是的,我知道,所以我把評論,以顯示代碼將工作的哪一行。 –

+0

那麼問題是什麼? – juanchopanza

回答

2

您不能分配常量對象。例如,考慮這個簡單的代碼

const int x = 10; 
x = 20; 

,編譯器會發出錯誤的第二次發言,因爲x是一個常量對象,並不得轉讓。

同樣是有效的for語句

(app1 = app2) = app3; 

這裏表達(app1 = app2)返回恆定參考其可以不被分配,

恆定的參考並不意味着對象本身,它指的是是恆定的。考慮以下示例

int x = 10; 
const int &rx = x; 

x = 20; 
rx = 30; 

雖然rx被定義爲常量引用,但您可以更改對象x本身。您可能不會使用該引用來分配對象x,因此編譯器將爲最後一條語句發出錯誤。

我們經常在函數的參數聲明中使用常量引用,以防止它們在函數內引用的對象發生變化。例如,

void f(const int &x) 
{ 
    x = 20; // compilation error 
} 

int x = 10; 

f(x); 

因此,定義對一個非常量對象的常量引用並不會使該對象本身保持不變。它只能防止使用此引用更改對象。

而且你需要定義只有一個拷貝賦值運算符

TestApp &operator=(const TestApp &obj) { 
     cout << "= operator\n"; 
     return *this; 
} // works for 1 

沒有任何需要定義拷貝賦值運算符,

TestApp &operator=(TestApp &obj) { 
     cout << "= operator\n"; 
     return *this; 
} // works for 2 

,如果你不打算更改右邊的操作數。所以最好把它定義爲一個常量基準const TestApp &obj

當然,你可能會把這兩個操作符放在一起,但是沒有任何意義可以擁有第二個操作符。

另一方面,你可能沒有隻有第二個操作符。在這種情況下,您將無法使用將其分配給其他對象的常量對象。

2

正確的方法提供了一個賦值運算符是如下聲明它:

TestApp &operator=(const TestApp &obj) { 
    cout << "= operator\n"; 
    return *this; 
} 

需要注意的是,只有一個const在右側的操作數,運營商本身和它的返回值是前未聲明const

這是錯誤的申報操作const因爲賦值運算符是意味着修改this對象。

而且它不必要地限制了使用操作符返回const引用,因爲調用者已經爲您提供了非const引用。因此,主叫方已經擁有非const訪問對象,所以返回const參考不必要阻止他從一個非const背景

這是當你做的雙重分配app1 = app2 = app3;會發生什麼重用的返回值:它評估爲app1 = (app2 = app3);,因此一個賦值的返回值作爲右側參數傳遞給下一個賦值。由第一個賦值返回的非const引用可隱式轉換爲const引用,因此此工作正常。

如果你的編譯器抱怨你的2號線與上面給出的聲明,則你的編譯器是難辭其咎的。我用gcc 4.7.2檢查了下面的代碼,它工作正常:

class Foo { 
    public: 
     Foo() {}; 
     Foo(const Foo& other) {} 
     Foo& operator=(const Foo& other) { return *this; } 
}; 

int main() { 
    Foo foo1, foo2, foo3; 
    (foo1 = foo2) = foo3; 
    foo1 = foo2 = foo3; 
}