簡體   English   中英

當我從類成員函數返回* this時,為什么要調用我的復制構造函數?

[英]Why is my copy constructor being called when I return *this from a class member function?

我知道我的副本構造函數和重載運算符在這種情況下是相當隨意的,但我找人驗證我是否正確地使用它們,以及正確使用*這個。

另外,有人可以告訴我為什么每次從任何重載運算符返回* this或Rectangle類型的對象時都會調用復制構造函數嗎?

class Rectangle
{
    private:
        int length;
        int width;
        static int counter;
    public:
        Rectangle(int len = 0, int w = 0)
        {
            length = len;
            width = w;
            counter++;
        }
        ~Rectangle()
            { counter--; }
        static int getCounter()
            { return counter; }

        Rectangle(const Rectangle &);
        Rectangle operator+ (const Rectangle &);
        Rectangle operator= (const Rectangle &);
};

int Rectangle::counter = 0;

Rectangle::Rectangle(const Rectangle &right) : Rectangle()
{
    width = right.width;
    length = right.length;
}

Rectangle Rectangle::operator+ (const Rectangle &right)
{
    width += right.width;
    length += right.length;
    return *this;
}

Rectangle Rectangle::operator= (const Rectangle &right)
{
    width = right.width;
    length = right.length;
    return *this;
}

其他人評論了如何通過值返回調用您的復制構造函數,所以我只是回答問題的第一部分:

如果我正確地使用它們,以及正確使用*這個。

您的運算符重載錯誤:

Rectangle Rectangle::operator+ (const Rectangle &right)
{
    width += right.width;
    length += right.length;
    return *this;
}

這會修改*this然后返回它的副本。 這不是你所期望的:

int b = 1, c = 2;
int a = b + c;

在上文中,b和c未經修改。 生成一個新值並存儲在a中。

Rectangle Rectangle::operator+ (const Rectangle &right) const
{
    Rectangle newValue(*this);  // copy ctor temporary
    newValue.length += right.length;
    newValue.width += right.width;
    return newValue;
}

或者如果你重載了operator+=你可以用它來寫它:

Rectangle Rectangle::operator+ (const Rectangle &right) const
{
    Rectangle newValue(*this);  // copy ctor temporary
    newValue += right;
    return newValue;
}

編譯器通常能夠執行返回值優化並忽略此代碼本來會產生的副本之一。

其次:

Rectangle Rectangle::operator= (const Rectangle &right)
{
    width = right.width;
    length = right.length;
    return *this;
}

正如您所了解的那樣,按值返回會返回一個副本。 operator =應該返回對當前對象的引用:

Rectangle& Rectangle::operator= (const Rectangle& right)
{
    width = right.width;
    length = right.length;
    return *this;
}

考慮

a = b = c;

這執行

a.operator=(b.operator=(c));

返回引用將為我們保存一個副本,生成參數到a.operator =。

我將完成這個使用* this的建議:

當您返回引用時,*這表示“返回對此類型的具體實例的引用”。 當你返回一個值而你說“* this”時,你會說“返回這個看起來像這個類的rvalue(可修改)實例”,它會調用一個副本。

當您按值返回對象時,將調用復制構造函數,該值需要在調用方復制。

Rectangle Rectangle::operator= (const Rectangle &right)
{
    width = right.width;
    length = right.length;
    return *this;     <<<<<<<< copy constructor call.
}

如果通過引用返回該對象,則可以避免此副本。

Rectangle& Rectangle::operator= (const Rectangle &right)
{
    width = right.width;
    length = right.length;
    return *this;     <<<<<<<<<<<< No copy constructor call.
}

另外,有人可以告訴我為什么每次從任何重載運算符返回* this或Rectangle類型的對象時都會調用復制構造函數嗎?

您的運算符返回Rectangle對象,這些對象必須根據存儲在*this中的Rectangle的值構造。 創建一個RectangleRectangle是拷貝構造函數做什么。

如果要返回this Rectangle本身(而不是副本),則需要返回對Rectangle的引用 - 所以Rectangle&

Rectangle & Rectangle::operator+ (const Rectangle &right)

在這種情況下,重載運算符是相當隨意的,但我正在尋找某人來驗證我是否正確使用它們,以及正確使用*。

不 - 不太正確。

Rectangle Rectangle::operator= (const Rectangle &right)通常被寫為返回一個Rectangle& ,因此可以對賦值的對象進行其他操作,它可以作為函數參數等傳遞。

Rectangle Rectangle::operator+(const Rectangle &right)實現不正確。 首先實現+=然后在+的實現中使用它是很常見的,但是如果你想獨立地編寫它,它可能是:

Rectangle Rectangle::operator+(Rectangle right) const
{
    right.width += width;
    right.length += length;
    return right;
}

這樣, right是參數是按值,因此對它的更改不會影響調用者,您可以修改它並按值返回。 這可能看起來效率低下,但是通常會優化掉按值返回(它稱為返回值優化 - RVO)。

我提到的另一種方法看起來像這樣......

Rectangle& operator+=(const Rectangle& rhs)
{
     length += rhs.length;
     width += rhs.width;
     return *this;
}

Rectangle operator+(Rectangle rhs) const
{
     return (rhs += *this);
}

也就是說,如果您的類型有任何隱式構造函數,則必須使+成為非成員運算符,因此左側參數會進行隱式構造的更改:

Rectangle operator+(const Rectangle& lhs, const Rectangle& rhs)
{
    return Rectangle(lhs.length + rhs.length, lhs.width + rhs.width);
}

另外,有人可以告訴我為什么每次從任何重載運算符返回*this或Rectangle類型的對象時都會調用復制構造函數嗎?

在你的問題的代碼中,返回類型是Rectangle (不是通過引用),並返回*this :它的作用是復制調用函數的對象並返回該副本。 復制構造函數用於創建副本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM