2017-11-25 254 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). 
}