【问题标题】:copy constructor is implicitly deleted because the default definition would be ill-formed复制构造函数被隐式删除,因为默认定义格式不正确
【发布时间】:2015-08-20 07:50:50
【问题描述】:

我有一个类A(来自一个我无法控制的库),它带有一个私有复制构造函数和一个clone 方法,以及一个派生自A 的类B。我也想为B 实现clone

天真的方法

#include <memory>

class A { // I have no control here
  public:
    A(int a) {};

    std::shared_ptr<A>
      clone() const
      {
        return std::shared_ptr<A>(new A(*this));
      }

  private:
    A(const A & a) {};
};

class B: public A {
  public:
    B(int data, int extraData):
      A(data),
      extraData_(extraData)
    {
    }

    std::shared_ptr<B>
    clone() const
    {
      return std::shared_ptr<B>(new B(*this));
    }

  private:
    int extraData_;
};

int main() {
  A a(1);
}

但是失败了,因为A 的复制构造函数是私有的:

main.cpp: In member function ‘std::shared_ptr<B> B::clone() const’:
main.cpp:27:42: error: use of deleted function ‘B::B(const B&)’
     return std::shared_ptr<B>(new B(*this));
                                      ^
main.cpp:17:7: note: ‘B::B(const B&)’ is implicitly deleted because the default definition would be ill-formed:
 class B: public A {
       ^
main.cpp:14:5: error: ‘A::A(const A&)’ is private
     A(const A & a) {};
     ^
main.cpp:17:7: error: within this context
 class B: public A {

可能有一种方法可以将A::clone() 用于B::clone(),但我不确定这将如何工作。有什么提示吗?

【问题讨论】:

    标签: c++ clone copy-constructor private-constructor


    【解决方案1】:

    我认为您的B 根本没有公共成员是一个错字, 并且您在B::B(int,int) 的定义之前缺少public:

    A 所代表的类的作者显然希望它是 可克隆但不可复制构造。这表明他或她想要所有 实例驻留在堆上。但相反,有公众 构造函数A::A(int)。你确定你是对的吗?

    假设该类可以揭示足够的信息是合理的 关于给定实例构成另一个实例。例如,放 A 多一点肉:

    class A {
    public:
        A(int a) 
        : data_(a){};
    
        std::shared_ptr<A>
        clone() const
        {
            return std::shared_ptr<A>(new A(*this));
        }
    
        int data() const {
            return data_;
        }
    
    private:
        A(const A & a) {};
        int data_;
    };
    

    如果这是真的,那么公共构造函数只会渲染它 不方便绕过私有的、未定义的复制构造函数:

    A a0(1);
    A a1{a0.data()};     // Inconvenient copy construction
    

    所以我不太相信A 忠实地代表了问题 班级。但是,从表面上看,您需要回答的问题 是:你能不方便地复制构造一个A吗?

    如果没有,那么你就卡住了。如果是这样,那么您可以使用不方便的副本 构造A 以明确定义B 的常规复制构造函数, 这就是你所需要的。例如

    class B: public A {
    public:
        B(B const & other)
        : A(other.data()),extraData_(other.extraData_){}    
    
        B(int data, int extraData):
        A(data),
        extraData_(extraData)
        {
        }
    
        std::shared_ptr<B>
        clone() const
        {
            return std::shared_ptr<B>(new B(*this));
        }
    
        int extradata() const {
            return extraData_;
        }
    
    private:
        int extraData_;
    };
    
    #include <iostream>
    
    int main()
    {
        B b(1,2);
        std::shared_ptr<B> pb = b.clone();
        std::cout << pb->data() << std::endl;
        std::cout << pb->extradata() << std::endl;
        return 0;
    } 
    

    【讨论】:

      【解决方案2】:

      B 的复制构造函数的默认定义格式错误的原因是 - 如果允许 - 它将调用私有的(因此 B 无法访问)并且未定义 A 的复制构造函数.

      A 的复制构造函数设为受保护或公开,以便B 可以访问它。另一个(非常糟糕的)选择是将B 类声明为A 的朋友。所有可能性还需要您为A 的复制构造函数提供定义。

      【讨论】:

      • 我无法控制 A,因为它来自库;我在原帖中澄清了这一点。
      • 根据我为回应该澄清(在 Nawaz 的帖子下方)所做的 cmets,拥有一个私有构造函数是一个非常重要的暗示,您不应该从 A 派生。
      • A::clone()也没有办法使用吗?
      【解决方案3】:

      您需要保护A 的复制构造函数,以便派生类可以使用它:

      protected:
          A(const A & a) { /*...*/ }
      

      希望对您有所帮助。

      【讨论】:

      • 我无法控制A,因为它来自图书馆;我在原帖中澄清了这一点。
      • 那么你不应该从A派生。
      • @NicoSchlömer:哦……在这种情况下,从A 派生是个坏主意。您现在应该使用组合,而不是继承。
      • A 派生是个坏主意。拥有一个私有(并且被省略)的复制构造函数是开发人员的一个相当大的提示,即不鼓励使用各种东西 - 包括使用 A 作为基类。
      • 这是一般规则吗:“不要从具有私有复制构造函数的类派生”?我现在不太明白为什么。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      • 1970-01-01
      • 2022-01-22
      • 1970-01-01
      • 2013-11-21
      相关资源
      最近更新 更多