[英]C++ an issue with returning a temporary object
您好,我用C ++大約一個月大了,所以如果這個問題太瑣碎,請原諒。
#include <iostream>
using namespace std;
class Point {
int x,y;
public:
Point(int x_val = 0,int y_val = 0) :x(x_val),y(y_val) { }
Point(Point& copy) : x(copy.x), y(copy.y) { }
void showLocation() const { cout << "[" << x << "," << y << "]" << endl; }
friend Point operator+(const Point& p1, const Point& p2);
friend Point operator-(const Point& p1, const Point& p2);
Point operator-(Point& p2) { // (1)
Point(x-p2.x, y-p2.y).showLocation();
return Point(x-p2.x, y-p2.y);
}
};
Point operator+(const Point& p1, const Point& p2) { // (2)
Point pos(p1.x+p2.x, p1.y+p2.y);
return pos;
}
Point operator-(const Point& p1, const Point& p2) { // (3)
return Point(p1.x-p2.x, p1.y-p2.y);
}
int main() {
Point p1(3,4);
Point p2(2,5);
(p1+p2).showLocation();
//(p1-p2).showLocation();
operator-(p1,p2);
}
因此,這是一個用於練習操作符重載的簡單代碼-我只是創建了一個點並重載了+和-運算符,它們都作為類的成員和全局函數。
但是,當我編譯此代碼時,我發現雖然(2)有效,但(1)和(3)都繼續顯示錯誤,我看不出為什么:
q1.cpp:17:10:錯誤:沒有匹配的構造函數來初始化'Point'返回Point(x-p2.x,y-p2.y); ^ ~~~~~~~~~~~~~~~~~~~~ q1.cpp:8:2:注意:候選構造函數不可行:第一個參數從'Point'到'int'的未知轉換
據我了解,(1)和(3)均應返回一個臨時Point對象,根據Google搜索,該對象應與情況(2)等效。
另外,錯誤語句使我更加困惑-我看不到在表達式中發生的任何轉換都是有問題的。
Point(x-p2.x, y-p2.y).showLocation();
這很好用,情況(2)也可以,所以我想這不是語法問題。 除了返回臨時對象(未命名)的問題的可能性之外,我看不到其他任何問題。
謝謝!
您可以通過簡單地刪除復制構造函數來解決此問題。 它沒有任何用處。 或者,您可以根據默認簽名在簽名中使用const
來修復副本構造const
。
Point(Point const & copy) : x(copy.x), y(copy.y) { }
如果沒有const
,則復制構造函數不能與臨時實例一起用作輸入。
資源:
這個:
Point(Point& copy) : x(copy.x), y(copy.y) { }
是技術上有效的副本構造函數 ,但它限制了可能的實際參數。
臨時或const
對象不能綁定到Point&
形式參數,因為這是對非const
的引用,這將允許修改實際參數。
相反,你可以寫
Point( Point const& other ): x( other.x ), y( other.y ) {}
在此我還糾正了誤導性參數命名的問題。
但更簡單的是,對於本課程,您可以
Point( Point const& other ) = default;
絕對最簡單,就是根本不定義一個復制構造函數,讓編譯器為您完成。
同樣,為了獲得最大的可用性,您應該更改
Point operator-(Point& p2) { // (1)
至
Point operator-(Point const& p2) const { // (1)
參數的const
表示現在可以使用const
或臨時(右值)參數調用它。
和const
的成員函數本身,最后一個const
,意味着它可以在一個被稱為const
對象。 這里的規則有些微妙。 與參數的限制相反,如果沒有const
則可以在臨時對象上調用它(即通過rvalue-expression)。
一般建議:
在幾乎可以使用的任何地方自由地散布const
,
讓編譯器生成復制操作, 除非您負責復制 ,並且
優先使用安全復制類型的數據成員,例如內置類型,智能指針和標准庫集合。
錯誤的原因(在您的情況下為(1))是
Point operator-(Point& p2) { // (1)
Point(x-p2.x, y-p2.y).showLocation();
return Point(x-p2.x, y-p2.y);
}
是Point(x-p2.x, y - p2.y)
產生一個臨時對象。 返回(語義上)需要創建臨時副本,這需要接受const
參數的副本構造const
。 您的副本構造函數不接受const
參數。
解決方案是修改您的副本構造函數以接受const
參數,或者將其徹底刪除(因為編譯器會自動生成一個對您而言正確工作的副本構造函數)。 在C ++ 11中,使用Point(const Point &) = default;
如果需要,可以強制編譯器生成正確的副本構造函數。
注意:該標准要求編譯器強制執行對正確的副本構造函數的需求,即使臨時文件已被優化為不存在也是如此。 這有助於提高代碼對未優化臨時文件的編譯器的可移植性。
代碼的另一個問題是您有兩種operator-()
變體。
您的情況(1)和(3)不相等。 第一個生成operator-()
的成員函數形式(接受一個參數,因為有一個隱含this
),第二個生成的非成員形式接受兩個參數。
當它看到一個類似p1-p2
的表達式(其中p1
和p2
都是Point
類型)時,該operator-()
兩個版本都是不錯的候選者。 編譯器會抱怨模棱兩可,因為沒有理由比另一個更偏愛一個。 所以一個聲明
(p1-p2).showLocation();
將無法編譯。 我認為您是出於這個原因將其注釋掉了。
解決方案是使用operator-()
一種形式或另一種形式。 不能一次全部。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.