复制具有继承功能的模板中的构造函数和赋值运算符

copy constructors and assignment operators in templates with inheritance

提问人:Andrew Voelkel 提问时间:3/15/2022 最后编辑:cigienAndrew Voelkel 更新时间:3/24/2022 访问量:209

问:

template<typename T = uint8_t> class ArrayRef {
  using uint = unsigned int;
protected:
  ArrayRef() {}
  ArrayRef(const ArrayRef&) {}
  ArrayRef& operator=(const ArrayRef& other) { return *this; }
};

class ByteArray : ArrayRef<uint8_t> {
  ByteArray(const ArrayRef&);
  ByteArray& operator=(const ArrayRef&);
public:
  ByteArray() {}
};

class Base {
  using uint = unsigned int;
protected:
  Base() {}
  Base(const Base&) {}
  Base& operator=(const Base& other) { return *this; }
};

class Derived : Base {
  Derived(const Derived&);
  Derived& operator=(const Derived& other) { return *this; }
public:
  Derived() {}
};

int main() {
  ByteArray ba;
  ByteArray ba2 = ba;  // no error, why?
  ba = ba2;            // no error why?
  Derived d;
  Derived d2 = d;      // error (expected) - Calling a private constructor
  d = d2;              // error (expected) - Calling private assignment operator
}

关于上面代码的两个问题。

  • 您能解释一下为什么模板化代码的行为与非模板化代码不同吗?(参见 main() 中的注释)。
  • 我将如何为这样的模板化代码正确地创建私有副本构造函数和赋值运算符,以防止对象复制?
C++ 模板 构造函数 Assignment-Operator

评论

0赞 김선달 3/15/2022
它与模板无关。我认为你应该改成.ByteArray(const ArrayRef&);ByteArray(const ByteArray&);

答:

2赞 Ted Lyngmo 3/15/2022 #1
  • 您能解释一下为什么模板化代码的行为与非模板化代码不同吗?(参见 main() 中的注释)。

区别与模板无关。

区别在于,复制构造函数和复制赋值运算符在 中隐式定义(如 )。在你做了它们.如果将模板排除在问题之外,可能会更容易看到两个版本之间的差异:publicByteArrayDerivedprivate

class ArrayRef {
protected:
    ArrayRef() {}
    ArrayRef(const ArrayRef&) {}
    ArrayRef& operator=(const ArrayRef& other) { return *this; }
};

class ByteArray : ArrayRef {
    ByteArray(const ArrayRef&);            // your converting ctor
    ByteArray& operator=(const ArrayRef&); // your converting assignment op
public:
    ByteArray() {}

    // copy contructor - implicitly defined:
    // ByteArray(const ByteArray&) = default;

    // copy assignment operator - implicitly defined:
    // ByteArray& operator=(const ByteArray&) = default;
};

如果您现在尝试复制一个,它将像基于类模板实例时一样正常工作。将上面的内容与实际制作的复制构造函数和复制赋值运算符进行比较。ByteArrayByteArrayDerivedprivate

  • 我将如何为这样的模板化代码正确地创建私有副本构造函数和赋值运算符,以防止对象复制?

为了防止复制,您可以:delete

class ByteArray : private ArrayRef<uint8_t> {
public:
    ByteArray(const ByteArray&) = delete;
    ByteArray& operator=(const ByteArray&) = delete;
    ByteArray() {}
};

或者让它们允许 S 和 S 制作副本:privateByteArrayfriend

class ByteArray : private ArrayRef<uint8_t> {
private:
    ByteArray(const ByteArray&) { ... }; // or `= default`
    ByteArray& operator=(const ByteArray&) { ...; return *this; } // or `= default`
public:
    ByteArray() {}
};

请注意,将 作为输入的(转换)构造函数和(转换)赋值运算符不会阻止隐式定义的复制构造函数和复制赋值运算符将 作为输入,该运算符来自 中创建的输入。privateconst ArrayRef<uint8_t>&const ByteArray&ByteArray

在您的类中,您实际上已经创建了复制构造函数和复制赋值运算符,这就是为什么您在尝试使用它们时会遇到预期的编译错误。Derivedprivate

下面是一个完整示例,其中包括 (转换) 构造函数和赋值运算符,以及 (用户定义的) 复制构造函数和复制赋值运算符。

#include <cstdint>
#include <iostream>

template<typename T = uint8_t> class ArrayRef {
protected:
    ArrayRef() {}
    ArrayRef(const ArrayRef&) {}
    ArrayRef& operator=(const ArrayRef& other) { return *this; }
};

class ByteArray : ArrayRef<uint8_t> {
    ByteArray(const ArrayRef&) { std::cout << "your converting ctor\n"; }
    ByteArray& operator=(const ArrayRef&) {
       std::cout << "your converting assignment op\n"; return *this;
    }
    
public:
    ByteArray(const ByteArray&) { std::cout << "copy ctor\n"; }
    ByteArray& operator=(const ByteArray&) {
        std::cout << "copy assignment op\n"; return *this;
    }
    ByteArray() {}
};

int main() {
    ByteArray a;
    ByteArray b = a;
    a = b;
}

您可以在输出中看到,没有使用任何方法:private

copy ctor
copy assignment op

评论

2赞 Quimby 3/15/2022
我也许会澄清一下,这是复制 ctor,不是。因此,正如您所说,公共的生成是为了。Derived(const Derived&);ByteArray(const ArrayRef&);ByteArray
0赞 Ted Lyngmo 3/15/2022
@Quimby 好主意。注释已添加。
0赞 Andrew Voelkel 3/18/2022
这个答案对我来说没有意义。模板版本和非模板版本之间的代码看起来相同。事实上,我复制了模板化代码并将其转换为非模板化代码,以确保它们在其他方面是相同的。你能详细说明一下吗?
0赞 Ted Lyngmo 3/18/2022
@AndrewVoelkel我稍微更新了一下答案。我希望现在更有意义。
0赞 Andrew Voelkel 3/24/2022
我需要认真思考,因为我心中的问题仍然是为什么模板化版本的行为与非模板化版本不同,而答案并没有直接解决这个问题。可能是我犯了一些愚蠢的错误来回答这个问题,但我还没有时间弄清楚是否是这种情况。我会开始的,但我有几天的假期,所以可能需要几天时间才能找到必要的思考时间。