2017-11-25 253 views
2

我的複製構造函數工作正常,但我不明白我的複製賦值操作符有什麼問題。具有多重繼承的複製賦值操作符

#include <iostream> 

template <typename... Ts> class foo; 

template <typename Last> 
class foo<Last> { 
    Last last; 
public: 
    foo (Last r) : last(r) { } 
    foo() = default; 
    foo (const foo& other) : last(other.last) { } 

    foo& operator= (const foo& other) { 
     last = other.last; 
     return *this; 
    } 
}; 

template <typename First, typename... Rest> 
class foo<First, Rest...> : public foo<Rest...> { 
    First first; 
public: 
    foo (First f, Rest... rest) : foo<Rest...>(rest...), first(f) { } 
    foo() = default; 
    foo (const foo& other) : foo<Rest...>(other), first(other.first) { std::cout << "[Copy constructor called]\n"; } 

    foo& operator= (const foo& other) { // Copy assignment operator 
     if (&other == this) 
      return *this; 
     first = other.first; 
     return foo<Rest...>::operator= (other); 
    } 
}; 

int main() { 
    const foo<int, char, bool> a(4, 'c', true); 
    foo<int, char, bool> b = a; // Copy constructor works fine. 
    foo<int, char, bool> c; 
// c = a; // Won't compile. 
} 

錯誤消息:

error: invalid initialization of reference of type 'foo<int, char, bool>&' from expression of type 'foo<char, bool>' 
     return foo<Rest...>::operator= (other); 
              ^

能有人在這裏指出的問題?

+0

爲什麼不使用複製和交換?你是否期望'不可交換或可衡量的性能問題? –

回答

7

你return語句

return foo<Rest...>::operator= (other); 

返回foo<Rest...>(這是與定義的參考operator=類型)。但它是從一個應該返回foo<First, Rest...>&的運營商那裏這樣做的。

本質上,您返回Base,其中Derived&預計參考。參考根本不會綁定。

幸運的是修復很簡單:不要返回foo<Rest...>::operator=的結果,而是返回*this

foo& operator= (const foo& other) { // Copy assignment operator 
    if (&other == this) 
     return *this; 
    first = other.first; 
    foo<Rest...>::operator= (other); 
    return *this; 
} 
+0

@故事出納是的的確如此。作爲獎勵,'if(&other == this)return * this;'被多次調用,但冗餘,正確(它只需要調用一次)?但沒辦法避免這種情況? – prestokeys

+0

@prestokeys - 您可以隨時將'operator ='委派給另一個不檢查(並且遞歸實現)的命名成員。 – StoryTeller

+0

@ StoryTeller答案已被接受,我實現了你的想法,在單獨的答案中進行優化。謝謝。 – prestokeys

1

貌似從operator=在派生類中返回不正確:

return foo<Rest...>::operator= (other); 

它返回基類,而應該是*this。將其更改爲

this -> foo<Rest...>::operator= (other); 
return *this; 
0

由於說書人,這裏是一個完全優化的編譯解決方案(運營商=委託給另一個名爲成員名稱copy_data不檢查自賦值,並遞歸執行):

#include <iostream> 

template <typename... Ts> class foo; 

template <typename Last> 
class foo<Last> { 
    Last last; 
public: 
    foo (Last r) : last(r) { } 
    foo() = default; 
    foo (const foo& other) : last(other.last) { } 

    foo& operator= (const foo& other) { 
     if (&other == this) 
      return *this; 
     last = other.last; 
     return *this; 
    } 
protected: 
    void copy_data (const foo& other) { 
     last = other.last; 
    } 
}; 

template <typename First, typename... Rest> 
class foo<First, Rest...> : public foo<Rest...> { 
    First first; 
public: 
    foo (First f, Rest... rest) : foo<Rest...>(rest...), first(f) { } 
    foo() = default; 
    foo (const foo& other) : foo<Rest...>(other), first(other.first) { std::cout << "[Copy constructor called]\n"; } 

    foo& operator= (const foo& other) { // Copy assignment operator 
     if (&other == this) 
      return *this; 
     first = other.first; 
//  foo<Rest...>::operator= (other); 
     foo<Rest...>::copy_data(other); 
     std::cout << "[Assignment operator called]\n"; 
     return *this; 
    } 
protected: 
    void copy_data (const foo& other) { 
     first = other.first; 
     foo<Rest...>::copy_data(other); 
    } 
}; 

int main() { 
    const foo<int, char, bool> a(4, 'c', true); 
    foo<int, char, bool> b = a; // Copy constructor works fine. 
    foo<int, char, bool> c; 
    c = b; // Copy assignment operator works fine (and optimized). 
}