【问题标题】:Copy assignment operator with multiple inheritance具有多重继承的复制赋值运算符
【发布时间】:2018-05-09 08:39:52
【问题描述】:

下面的复制构造函数工作正常,但我不明白我的复制赋值运算符有什么问题。

#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);
                                              ^

有人能指出这里的问题吗?

【问题讨论】:

  • 为什么不使用复制和交换?您是否认为Ts 存在不可交换或可测量的性能问题?

标签: c++ c++11 templates inheritance assignment-operator


【解决方案1】:

您的退货声明

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

返回一个foo&lt;Rest...&gt;(这是operator= 定义的引用类型)。但它是从一个应该返回 foo&lt;First, Rest...&gt;&amp; 的运算符执行的。

基本上,您返回一个Base,其中需要一个Derived&amp; 引用。引用根本不会绑定。

幸运的是,修复很简单:不要返回 foo&lt;Rest...&gt;::operator= 的结果,而是返回 *this

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

【讨论】:

  • @Story Teller 是的,确实如此。作为奖励,if (&amp;other == this) return *this; 被多次调用,但是是多余的,对吧(它只需要调用一次)?但没有办法避免这种情况?
  • @prestokeys - 你总是可以让operator= 委托给另一个不检查(并且递归实现)的命名成员。
  • @StoryTeller 答案已接受,我实施了您的想法以在单独的答案中对其进行优化。谢谢。
  • @prestokeys 您可能实际上并不想递归地实现任何东西。改用包扩展。在这些情况下可以节省大量的模板膨胀。
【解决方案2】:

看起来派生类中operator=的返回不正确:

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

它返回基类,而它应该是*this。改成

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

【讨论】:

    【解决方案3】:

    感谢 StoryTeller,这是一个优化的完全编译解决方案(operator= 委托给另一个命名的成员名称 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).
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-28
      • 1970-01-01
      • 2021-08-28
      • 2021-06-07
      • 2015-02-09
      • 2017-11-21
      • 1970-01-01
      • 2020-12-15
      相关资源
      最近更新 更多