【问题标题】:What happens when we make base class copy constructor private?当我们将基类复制构造函数设为私有时会发生什么?
【发布时间】:2021-03-25 18:31:08
【问题描述】:

我们无法复制派生类对象,当基类的复制构造函数是私有的,但是当我们在派生类中编写自己的复制构造函数时,我们可以复制对象,为什么?

#include <iostream>
class base
{
public:
    base()
    {
    }

private:
    base(const base &x)
    {
        std::cout << "copy constructor of base class";
    }
};
class derived : public base
{
public:
    derived(){};
    derived(const derived &X)             //If we remove this, we are not able to create copy? But why?
    {
        std::cout << "copy of derived class";
    }
};

int main()
{
    derived x;
    derived y(x);//valid with our own derived class copy constructor 
}

看了cmets和answer后才明白这一点,我又写了一个程序

#include <iostream>
class base
{
protected:
    int x;
    int y;
public:
    base() {}
    base(int x, int y) : x(x), y(y)
    {
    }
};
class derived : public base
{
    int a;

public:
    derived()
    {
    }
    derived(int a, int x, int y) : a(a), base(x, y){};
    derived(derived const &x)
    {
        this->a = x.a;
    }
    void get()
    {
        std::cout << a;
        std::cout << "\t" << x << "\t" << y;
    }
};
int main()
{
    derived a(99, 2, 3);
    a.get();
    derived b(a);
    std::cout << std::endl;
    b.get();
}

这给了我输出

99      2       3
99      -2145089504     1

我还发现 Why aren't copy constructors "chained" like default constructors and destructors? 值得一读

【问题讨论】:

  • 您的构造函数derived(const derived &amp;X) 默认调用base(),这是公共的,如果需要,您必须显式调用基类复制构造函数(因为它是私有的,所以会失败)。编译器生成的derived 的复制构造函数调用base 的复制构造函数,这是私有的,这就是它之前失败的原因。
  • @MartinYork 如果我删除它并使用编译器的复制构造函数会发生什么?
  • 见上面的评论。
  • @MartinYork 谢谢伙计!!
  • 在您的第二个代码块中,get() 例程在 xy 未初始化时执行未定义行为

标签: c++ copy-constructor


【解决方案1】:

当基类的复制构造函数为私有时,我们无法复制派生类对象

派生类副本的隐式复制构造函数初始化基类。如果 base 的复制构造函数是私有的,那么派生类就无法访问它,也无法复制基类。如果您明确定义不复制基类的派生类复制构造函数,则没有问题 - 除了基类被默认初始化的问题。

【讨论】:

    【解决方案2】:

    我认为您假设 derived 的复制构造函数将调用 base 的复制构造函数,但事实并非如此,它调用了构造函数。正如在 cmets 中所说,您需要显式调用复制构造函数才能获得默认行为。

    此外,当基类复制构造函数为私有时,编译器通过删除派生类的复制构造函数来维护默认行为。

    所以编译器会同时删除复制构造函数和赋值运算符

      // derived(const derived &) = delete;
      // derived(derived &&) = delete;
    
    

    在您的情况下,您显式声明了复制构造函数,因此编译器永远不需要显式删除它们。

    【讨论】:

      猜你喜欢
      • 2012-09-15
      • 2011-02-04
      • 2020-10-29
      • 1970-01-01
      • 2017-09-20
      • 1970-01-01
      • 2017-07-20
      • 2023-04-09
      • 2015-09-21
      相关资源
      最近更新 更多